-9

私は gcc を使用しており、次のような小さなプログラムを作成しています。

#include<stdio.h>

void doing(){
    char buf[4096 + 1];
    printf("buf %d\n", buf);
    printf("buf %f\n", buf);
    printf("buf %d\n", (unsigned) buf);
    printf("buf %s\n", buf+2);
    printf("buf %d\n", buf+2);

}


int main (void){
    char buf[4096 + 1];
    printf("(unsigned) buf %d\n", (unsigned) buf);
    doing();
    printf("(unsigned) buf %d\n", (unsigned) buf);
    return 0;
}

プログラムの出力は次のとおりです。

(unsigned) buf 2268303
buf 2264159
buf 0.000000
buf 2264159
buf
buf 2264161
(unsigned) buf 2268303

2268303 を整数として出力する理由と、この 2268303 値がどこから来て、1 つの関数が値を 2268303 として、別の関数が 2264159 を与えているのかわかりません

4

4 に答える 4

1

少し分解して、コードの各行について次のように説明できることを見てみましょう。

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]printfintsizeof(int)

buf 2264159

bufこれは、 indoingが から 4144 バイト離れて割り当てられmain、スタックが下向きに成長することを強く示唆しています。

    printf("buf %f\n", buf);

もう一度、配列からポインターへの変換がありprintfdouble引数が必要ですが、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]場所に渡されます。型の不一致は未定義の動作を引き起こしますが、出力はprintfint

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;
}
于 2013-04-12T09:19:56.020 に答える
1

Cの基本を読んでください。あなたはあなたの答えを得るでしょう。

それにかんする、

1 つの関数は 2268303 として値を与え、別の関数は 2264159 を与えています

1 つの char buf[] が main() で宣言され、もう 1 つが doing() で宣言されていることに注意してください。どちらも異なるストレージを持ち、どちらも独自のスコープで機能します。[C の変数のスコープを読む]

于 2013-04-12T08:09:10.070 に答える
0

説明は次のとおりです。

これ:

printf("buf %d\n", buf);

「buf」配列の最初の要素のアドレス(メモリ位置)を出力します

これ:

printf("buf %f\n", buf);

"buf" 配列の最初の要素のアドレスから float を読み取ろうとしますが、printf はおそらく 0 を返します。

これ:

printf("buf %d\n", (unsigned) buf);

「buf」のアドレスは常にゼロ以上であるため、最初の printf と同じことを行います。

これ:

printf("buf %s\n", buf+2);

"buf" 配列の最初の要素のアドレスから float を読み取ろうとしますが、printf はおそらく空の文字列を返します。

ついに:

printf("buf %d\n", buf+2);

「buf」配列の3番目の要素から離れた位置を返します

注意すべき重要事項: 宣言した 2 つの「buf」配列 (1 つは main 内、もう 1 つは doing() 内) は、同じ名前を付けたとしても、2 つの異なる配列です。doing() 内の "buf" はそこで作成したものを指し、main 内の "buf" もそこで作成したものを指します。これが、実行中またはメインから印刷するときに2つの異なるアドレスを取得する理由です

于 2013-04-12T08:14:30.800 に答える
0

使用%pすると、値が取得されhexます。また、スコープもブラッシュアップする必要があります。これらの リンクも参照してください。

(unsigned) buf 2268303 // You have defined this in main its a local array so it has                      
                       //2268303 as address. And for an array the array name acts as a 
                       //pointer too
buf 2264159            // You have defined this in fn doing, it is local to that function     
                       //and has a different address (it is a different array than the one 
                       //in your main)
于 2013-04-12T08:09:09.310 に答える