Renesas Synergy™

FAQ 104088 : ポインタへの加減算が期待値になりません。

Q: 質問

ポインタへの加減算が期待値になりません。

 


A: 回答

例えば下記のプログラムにおいて、


long *p = (long*)0x1000;
long a = *(p+8);

この演算により、0x1008番地から4バイトデータをロードすることを期待していたとすると、
それは文法的に間違いであり、実際の動作は0x1020番地から4バイトデータをロードすることになります。
期待している動作をさせるためには、

a = *(p+2); /* 2 == 8 / sizeof(long) */

または、

a = *((long*)((char*)p + 8));

と記述する必要があります。 同様に、

long *p = (long*)0x1000;
p += 8;

この演算により、p が 0x1008 になることを期待していたとすると、
それも文法的に間違いであり、実際の動作は p は 0x1020 になります。
期待している動作をさせるためには、

p += 2; /* 2 == 8 / sizeof(long) */

または、

p = (long*)((char*)p + 8);

と記述する必要があります。
この解説のために、ポインタと配列の関係について説明致します。
ポインタと配列は、それらを同等に扱えるほど非常に強い関係を持っています。
例えば下記のプログラムにおいて、(1-1)、(1-2)、(1-3)、(1-4)は どれも同じ意味となり、
同じ結果が得られます。
同様に、(2-1)、(2-2)、(2-3)、(2-4)はどれも同じ意味となります。

int n;
long x;
long a[10];
long* p = a;
void main()
{
x = a[2]; // (1-1)
x = *(a+2); // (1-2)
x = p[2]; // (1-3)
x = *(p+2); // (1-4)
x = a[n]; // (2-1)
x = *(a+n); // (2-2)
x = p[n]; // (2-3)
x = *(p+n); // (2-4)
}

(1-2)、(1-4)に記述された「a+2」、「p+2」は、配列 a の先頭アドレス、
または、long型へのポインタ p から、2要素分先のアドレスを示すことを意味しています。
ここで、1要素のサイズは sizeof(long) ( = 4) であり、2要素のサイズは、2 * sizeof(long) ( = 8) となります。
したがって、a、 p から8バイト先のアドレスを示すことになります。

これに対し、「(char*)p + 8」のように一旦 char型へのポインタにキャストする場合には、
1要素のサイズは sizeof(char) ( = 1) であるため、加算したバイト数分 先のアドレスを示します。

なお、(1-1)、(1-3)のように記述する場合には、何要素先なのかを意識することはあっても、
何バイト先なのかを意識する必要は特になく、コンパイラがその要素のサイズを元に、
何バイト先になるのかを自動的に解釈します。
同様なことが、ポインタへの減算、および、代入演算子(+=、-=)でも言えます。
また、long型へのポインタだけではなく、short型へのポインタや構造体、共用体、
クラスへのポインタでも同様なことが言えます。

したがって、ポインタに対して加算(減算)する場合には、その加算値(減算値)を
バイト数で解釈させたいのか、要素数で解釈させたいのかに注意し、バイト数で解釈
させたい場合には一旦 char型へのポインタにキャストして下さい。

 

適用製品

SuperHファミリ用C/C++コンパイラパッケージ
H8SX,H8S,H8ファミリ用C/C++コンパイラパッケージ
他にご質問がございましたら、リクエストを送信してください