1

この質問への回答でこの関数に出くわしました:

/* Note: I've formatted the code for readability. */
const char * getString() {
    const char *x = "abcstring";
    return x;
}

リテラル文字列へのポインターを返すことが機能し、思ったほどセグメンテーション違反を起こさなかったことを発見して驚きました。リテラルはスタックにプッシュされるか、他の一時メモリに置かれると常に想定していましたが、関数のスコープに限定されていました。しかし、ここでは、私が想像していたよりも静的なようです。次に、実行可能ファイル全体にグローバルな文字列プールのようなものに入れられますか?

また、文字列リテラルをパラメータとして関数に渡しても同じですか?例えば:

/* Where is the string literal in this example being placed? */
myfunc(value1, value2, "rainbowdash");

誰かが私を啓発できることを願っています。前もって感謝します!:)

4

3 に答える 3

6

C では、文字列リテラルには静的な保存期間があります。あなたのコードは論理的に次のものと同等です。

const char * getString() {
    static const char literal[] = "abcstring";
    const char *x = literal;
    return x;
}

ただし、文字列リテラルを使用するバージョンでは、文字列のストレージが他の文字列リテラルのストレージと重複する可能性があります。

于 2012-06-16T04:11:06.123 に答える
3

他のほとんどの回答の補遺として、コンパイラが生成するアセンブラを見て(たとえば、-SGCCに渡すことによって)、それらがどのように格納されているかを確認できます。関数を単独でファイルに入れると、GCC が基本的に生成することがわかります (関係のないものをいくつか削除しました)。

.section        .rodata
.LC0:
        .string "abcstring"
        .text

        .globl  getString
        .type   getString, @function
getString:
        # load the address of ".LC0" which is the start of the "abcstring"
        movl    $.LC0, %eax 
        ret

そのため、文字列はスタックではなくセクション (「読み取り専用データ」) に格納されるため.rodataグローバル」アドレスを持ちます (常にスコープ内にあります)。

同様に、文字列リテラルmyfunc("thisisastring").rodataセクションに配置され、スタックにはありません。

于 2012-06-16T04:20:21.347 に答える
1

ABIごとに異なりますが、x86では、DSレジスタが指す静的メモリ/DATAページにあります。

于 2012-06-16T03:24:45.380 に答える