2016-04-27 7 views
2

チェックこのCプログラム:上記のコードを実行sizeofで使用するときにNULLポインタにアクセスする方法を理解するには?

#include <stdio.h> 

int main(void) { 
     // your code goes here 
     char **p = NULL; 

     printf("%d,%d\n", sizeof(*p), sizeof(**p)); 
     return 0; 
} 

、結果は次のとおりです。

8,1 

pNULLですが、それはsizeof(*p)sizeof(**p)でプログラムのクラッシュを引き起こすことはありません。この行動を理解するには? 仕様で保証されていますか?

+0

'sizeof(* p)'は 'sizeof(char *)'と 'sizeof(** p)'だけです 'sizeof(char)'です –

+0

警告:UBは保証しませんとにかく_crash_。 –

答えて

5

sizeof演算子はコンパイル時に評価されます。そのオペランドは副作用について評価されないので、プログラムは安全です。これは、標準6.5.3.4/2(強調鉱山)によって保証されている:

オペランドの型が可変長配列型である場合、 オペランドが評価されます。そうでなければ、オペランドは評価されず、結果は整数定数です。

(評価は実行時に行われるので、コードはsizeof内部VLAへの無効なポインタをデ参照すると安全ではないと思われる場合には可変長配列の特別な場合があることに注意してください。)

sizeofの結果を印刷する際にサイドノート、printfのための正しいフォーマット指定子として(sizeofの結果はタイプsize_tある)%zuあります。

2

オペランドsizeofは評価されていません。つまり、pは決して参照されないため、未定義の動作ではありません。 64ビットシステムでは、ポインタは8バイト幅になり、charは常に1バイトになり、出力が説明されます。

4

sizeof(exp)はコンパイル時の演算子であり、式expを実行時に評価しないためです。

結果として、実行時にNULLポインタの参照がありません。最終的なバイナリのprintf文には、定数の同等のマシンコードしかありません。

3

ご存知のとおりpchar**ですので、sizeof(*p) == sizeof(char*)です。実際には逆参照は必要ありません。

同じことがsizeof(**p)に適用されます。コンパイル時にサイズを把握することができないため、逆参照を行う必要はありません。

関連する問題