[C言語入門] 演算子の使い方(4)
高木です。おはようございます。
C言語の「演算子の使い方」は結構なボリュームになってしまいました。
今回はアドレス演算子よ間接演算子の解説を行います。
まだまだ完結しそうにありませんので、次回以降に続くことになります。
それでは早速始めましょう。
アドレス演算子と間接演算子
アドレス演算子は記号&で表します。
&を使う演算子はほかにもあるので注意してください。
アドレス演算子のオペランドは、関数指示子(ほとんど場合は関数名です)、添字演算子や間接演算子の結果、あるいは左辺値でなければなりません。
また、ビットフィールドやregister記憶クラス指定子を付けて宣言されたオブジェクトはオペランドに指定できません。
1 2 3 4 5 6 7 8 9 10 11 12 | int a; &a; // OK &+a; // エラー(右辺値) struct B { int f : 1; } b; &b.f; // エラー(ビットフィールド) register int c; &c; // エラー(register記憶クラス指定子付き) |
アドレス演算子の評価結果は、そのオペランドのアドレスです。
アドレスの型はオペランドの型へのポインタ型です。
1 2 3 4 5 6 7 | int a; int *pa = &a; // intへのポインタ型 int **ppa = &pa; // int*へのポインタ型 int array[10]; int (*parray)[10] = &array; // int[10]へのポインタ型 int *pb = &array[0]; // intへのポインタ型 |
ここでいうアドレスは、必ずしもハードウェア的なアドレスとは一致しません。
ただ、現実的には、余程特殊なケースを除けば、CPUのアドレスを表す整数値をポインタ型にキャストしたものに一致するようです。
マイコンのプログラミングでは、実際にそのようにしてI/Oポートにアクセスすることが多々あります。
C言語におけるアドレスの型はポインタ型であり、ポインタの値の多くはアドレスです。
アドレスとポインタは同じではありませんが、切っても切れない関係にあるといってよいでしょう。
間接演算子は*で表します。
乗算演算子と間違わないように注意してください。
間接演算子のオペランドはポインタ型でなければなりません。
オペランドが関数へのポインタ型の場合、評価結果は関数指示子になります。
オペランドがオブジェクト型へのポインタ型の場合、評価結果はその指しているオブジェクト型の左辺値になります。
1 2 3 4 5 6 7 | int func(void); int (*pfunc)(void) = &func; *pfunc; // 関数指示子(func) int a; int *pa = &a; *pa; // (オブジェクト型の一種である)int型の左辺値 |
間接演算子のオペランドが正しいアドレスではない場合は未定義の動作になります。
また、オペランドが不完全型へのポインタの場合も未定義の動作になります。
1 2 3 4 5 6 | int a; void *pa = &a; *pa; // 未定義の動作(voidは不完全型) struct B *pb = /* 正しいアドレス */; *pb; // 未定義の動作(struct Bは構造体の内容が定義されていないので不完全型) |