少し分解して、コードの各行について次のように説明できることを見てみましょう。
int main (void){
char buf[4096 + 1];
を宣言するchar[4097]
と、通常、 が入力されたときにスタック ポインターを調整してスタックに割り当てられますmain
。配列の内容は不定です。
printf("(unsigned) buf %d\n", (unsigned) buf);
&
配列型の式は、それがアドレス ( )sizeof
または演算子のオペランドでない限り_Alignof
、または文字配列の初期化に使用される文字列リテラルでない限り、配列の最初の要素へのポインターに変換されます (6.3.2.1 p. 3 )、その行はと同等です
printf("(unsigned) buf %d\n", (unsigned) &buf[0]);
の最初のバイトのアドレスを取得しbuf
、それを に変換してunsigned
、結果の数値を符号付き整数として出力します。unsigned
結果の値が として表現できない場合、動作は未定義であることに注意してくださいint
。&buf[0]
へのポインターの変換unsigned
は実装定義であり、未定義の動作を引き起こす可能性があります (6.3.2.3 p. 6)。通常、sizeof(unsigned)
ポインター値のバイトは符号なし整数として解釈されます (通常、ポインターのサイズが のサイズよりも小さくないことが含まれますunsigned
)。あなたの場合、結果は
(unsigned) buf 2268303
印刷されました。次
doing();
それでは、見てみましょうdoing
:
void doing(){
char buf[4096 + 1];
もう 1 つchar[4097]
は宣言されています。通常は、doing
入力時にスタック ポインターを調整することによって割り当てられます。この配列の内容も不確定です。
printf("buf %d\n", buf);
繰り返しますbuf
が、 type の式は、つまりにchar[4097]
変換され、引数が必要な に渡されます。型の不一致は未定義の動作を引き起こします。通常、ポインター値のバイトは符号付き整数として解釈されます。結果は出力ですchar*
&buf[0]
printf
int
sizeof(int)
buf 2264159
buf
これは、 indoing
が から 4144 バイト離れて割り当てられmain
、スタックが下向きに成長することを強く示唆しています。
printf("buf %f\n", buf);
もう一度、配列からポインターへの変換がありprintf
、double
引数が必要ですが、char*
. より未定義の動作、明示は次のとおりです
buf 0.000000
印刷されます。それがどうなるかは、一般的には答えられません (結局のところ、未定義の動作です)。64 ビット システムでは、一般的な動作はprintf
、ポインターまたは整数型の引数が汎用レジスターで渡され、浮動小数点引数が浮動小数点レジスターで渡されることです。そのため、printf
たまたま 0 の値が含まれている浮動小数点レジスタが読み取られます。
printf("buf %d\n", (unsigned) buf);
この行は の対応する行と同じセマンティクスを持っていますがmain
、別の arraybuf
であるため、変換から得られる (符号なし) 整数は異なります。
buf 2264159
printf
の最初のものと同じものを出力しますがdoing
、これは驚くべきことではありません (ただし、未定義の動作が関係しているため、保証されません)。
printf("buf %s\n", buf+2);
buf
が に変換され&buf[0]
、それに 2 が加算されて になり&buf[2]
ます。これは に渡されprintf
、%s
変換により、 の 0 で終わる配列へのポインタがchar
引数として期待されます。これは、の 2 番目の引数の型が、変換指定子により期待される型と正確に一致する、printf
プログラム全体で唯一の呼び出しです。printf
ただし、 の内容buf
は不定であるため、配列に 0 バイトがないと、 による無効な読み取りが発生しますprintf
。しかし、どうやらbuf[2]
0 だったので、
buf
印刷されました。
printf("buf %d\n", buf+2);
buf + 2
は再び に評価され、それは が期待する&buf[2]
場所に渡されます。型の不一致は未定義の動作を引き起こしますが、出力はprintf
int
buf 2264161
は何も悪いことが起きていないことを示しており、&buf[2]
は 2 バイト遅れているため、出力&buf[0]
される数値はdoing
の最初ので出力される数値よりも 2 大きくなりprintf
ます。
}
に戻るmain
:
printf("(unsigned) buf %d\n", (unsigned) buf);
その行は の最初のprintf
呼び出しと同じmain
であるため、上記で説明したのと同じセマンティクスを持ちます。
(unsigned) buf 2268303
そして同じ出力を生成します。
return 0;
}