前々から、C言語のポインタで不思議だったこと。
最適化C 言語 より
http://www.imit.chiba-u.ac.jp/new-system/sr/man_hitachi_c/MAN/3000/03C3100D/C310057.HTM
>単項&演算子をアドレス演算子といい,&の後に続くオペランドのポインタ(アドレス)を表します。
>(3) 記述例
>int a , *p ;
>p = &a ;
> 解説
> &aはaのアドレスを表し,ポインタpにaのアドレスを代入する式です。
こういうのを見て、アドレス演算子をつければ、
その変数のアドレスが分かるって理解しちゃうと不思議なことが起きます。
例えば、
#include <stdio.h> main() { int target; int x = &target + 1; int y = ⌖y += 1; printf("x = %d\ny = %d\n",x,y); }
のようなコード。xとyが同じ値になりません。
友人に色々教えてもらい分かったことなのですが、
「数値とアドレスは違うもの。&をつけるとポインタ型になる。」ということ。
考えれば、普通は変数にアドレス演算子をつけたものは、ポインタ型にエラーなく代入してますよね。
つまり、アドレスの型は、ポインタ型なのです。
なお、ポインタ型同士の加算は出来ないです。
&target + &target ←エラー
実際の計算的には
int x = &target + n; → int x = (int)&target + sizeof(target) * n;
X型のポインタ型に、数値を加算する場合に、自動でsizeof(X)を数値に掛け算してくれます。
数値ではなく、ポインタ型の場合はエラー。
HSPをやっていると、varptr函数でアドレスが分かるのですが、
アドレス演算子は、それと同じようなものだと思っていたわけですが、こんな違いがあったのですね。
あとあと、教科書やサイトとかで、ポインタ型を%pではなく整数型を表示させる%dで表示するもんだから、
なんか、「アドレスと整数は同じなんだ。アドレスって数値だし納得!」みたいな錯覚するというか。
後で調べたのですが、ポインタに関して、
苦しんで覚えるC言語のアドレスを記憶する変数 がつっこんだところまで解説していて分かりやすいです。
まあそれはおいておいて、友人が書いたサンプル。
#include <stdio.h> main() { int x = 1,y[] = {0,100}; printf("%d\n",x[y]); }
という書き方のほうが驚いた。
y[2] が *(y+2) に対応しているから、こういう書き方できるそうです。
C言語は奥が深いです。
いろいろ教えてくださって、ありがとうございます。m(_ _)m
ポインタ型同士の加算・ポインタ型に数値の掛算・割算はエラー。
#include <stdio.h> main() { int* target; target = (int *)1 + (int *)2; target = (int *)1 * 1; target = (int *)1 / 1; }
以上のことが分かると、次のようなネタコードが書けます。
ビットシフト無しで1バイトずつ取り出す。(1回の加算と1回のビット論理和)
#include <stdio.h> #define GET(T,N) ((int)*((char*)(&T)+(int)(N))) main() { int i,target = 0×11223344; for(i=0;i (すみません。ブログの仕様変更で消えてしまった!)
加算のみで5の倍数を表示する。(3回の加算)
#include <stdio.h> #define GET(T,N) (int)((T*)0+(int)(N)) main() { int X = 8; printf("%d\n",GET(long,X)+GET(char,X)); }
コメント