32

文字列リテラルは関数の外部で定義されていないのではないかと心配しているので、私は常に文字列リテラルを返さないようにしています。しかし、これが当てはまるかどうかはわかりません。たとえば、次の関数を見てみましょう。


const char *
return_a_string(void)
{
    return "blah";
}

これは正しいコードですか?それは私にとっては機能しますが、おそらく私のコンパイラ(gcc)に対してのみ機能します。したがって、問題は、(文字列)リテラルにスコープがあるのか​​、それとも常に存在/定義されているのかということです。

4

7 に答える 7

46

このコードは、すべてのプラットフォームで問題ありません。文字列は、静的文字列リテラルとしてバイナリにコンパイルされます。たとえば、Windows を使用している場合は、メモ帳で .exe を開いて文字列自体を検索することもできます。

これは静的文字列リテラルであるため、スコープは重要ではありません。

文字列プーリング:

注意すべきことの 1 つは、場合によっては、同一の文字列リテラルを「プール」して、実行可能ファイルのスペースを節約できることです。この場合、同じだった各文字列リテラルは、同じメモリ アドレスを持つことができます。ただし、そうなるかどうかは決して想定しないでください。

ほとんどのコンパイラでは、リテラルの攪拌に静的文字列プーリングを使用するかどうかを設定できます。

文字列リテラルの最大サイズ:

いくつかのコンパイラには、文字列リテラルの最大サイズがあります。たとえば、VC++ の場合、これは約 2,048 バイトです。

文字列リテラルを変更すると、未定義の動作が発生します。

文字列リテラルの変更は絶対に行わないでください。未定義の動作があります。

char * sz = "this is a test";
sz[0] = 'T'; //<--- undefined results

ワイド文字列リテラル:

上記のすべては、ワイド文字列リテラルにも同様に適用されます。

例: L"これはワイド文字列リテラルです";

C++ 標準の状態: (セクション lex.string)

1 文字列リテラルは、二重引用符で囲まれた一連の文字 ( lex.cconで定義されている) であり、オプションで "..." または L"..." のように文字 L で始まります。L で始まらない文字列リテラルは通常の文字列リテラルであり、ナロー文字列リテラルとも呼ばれます。通常の文字列リテラルの型は「n const char の配列」で、静的な保存期間 ( basic.stc)、ここで、n は以下で定義される文字列のサイズであり、指定された文字で初期化されます。L"asdf" などの L で始まる文字列リテラルは、ワイド文字列リテラルです。ワイド文字列リテラルは、"array of n const wchar_t" 型を持ち、静的な保存期間を持ちます。ここで、n は以下で定義される文字列のサイズであり、指定された文字で初期化されます。

2 すべての文字列リテラルが異なる (つまり、重複しないオブジェクトに格納されている) かどうかは、実装によって定義されます。文字列リテラルを変更しようとした場合の影響は未定義です。

于 2008-11-05T23:25:33.740 に答える
12

あなたの混乱がいくらか明確になるように、例を挙げます

char *f()
{
char a[]="SUMIT";
return a;
}

これはうまくいきません。

しかし

char *f()
{
char *a="SUMIT";
return a;
}

これは機能します。

理由:"SUMIT"グローバル スコープを持つリテラルです。文字のシーケンスである配列は{'S','U','M','I',"T''\0'} 範囲が限られており、プログラムが返されるとすぐに消えます。

于 2011-09-07T09:21:05.020 に答える
6

他の人が説明したように、これは C (または C++) で有効です。

私が気をつけなければならないことの 1 つは、DLL を使用している場合、このコードを含む DLL がアンロードされるとポインタが有効なままにならないということです。

C (または C++) 標準は、実行時のコードのロードとアンロードを理解していないか、考慮していません。静的ストレージ期間は、呼び出しコードの POV から、プログラムの全期間にわたって持続しないように見えます。

于 2008-11-07T14:08:08.560 に答える
3

はい、大丈夫です。それらはグローバル文字列テーブルに存在します。

于 2008-11-05T23:25:39.120 に答える
3

いいえ、文字列リテラルにはスコープがないため、コードはすべてのプラットフォームとコンパイラで動作することが保証されています。これらはプログラムのバイナリ イメージに格納されるため、いつでもアクセスできます。ただし、( をキャストして) それらに書き込もうとすると、const未定義の動作が発生します。

于 2008-11-05T23:26:47.747 に答える
0

ブライアンが言及した未定義の結果に注意することは非常に重要です。関数が const char * 型を返すと宣言しているので問題ないはずですが、多くのプラットフォームでは文字列リテラルが実行可能ファイルの読み取り専用セグメント (通常はテキスト セグメント) に配置されており、それらを変更するとアクセス違反が発生します。ほとんどのプラットフォームで。

于 2008-11-06T00:40:15.540 に答える
0

実際には、実行可能ファイルのデータ セクション (プログラムのロード時にロードされる領域) に格納されている、ゼロで終わる文字列へのポインターを返します。文字を変更しようとするのは避けてください。予測できない結果になる可能性があります...

于 2008-11-05T23:28:04.640 に答える