web-dev-qa-db-ja.com

文字列リテラルがl値であるのに、他のすべてのリテラルがr値であるのはなぜですか?

C++ 03 5.1一次式§2言います:

リテラルは主要な式です。そのタイプはその形式(2.13)によって異なります。文字列リテラルは左辺値です。他のすべてのリテラルは右辺値です。

同様に、C996.5.1§4は次のように述べています。

文字列リテラルは主要な式です。 6.4.5で詳述されているタイプの左辺値です。

これの背後にある理論的根拠は何ですか?

私が理解しているように、文字列リテラルはオブジェクトですが、他のすべてのリテラルはそうではありません。また、l値は常にオブジェクトを参照します。

しかし、問題は、他のすべてのリテラルがオブジェクトではないのに、なぜ文字列リテラルがオブジェクトなのかということです。この理論的根拠は、私には卵が先か鶏が先かという問題のように思えます。

これに対する答えは、プログラミング言語としてのC/C++ではなくハードウェアアーキテクチャに関連している可能性があることを理解していますが、それでも同じことを聞きたいと思います。

53
Alok Save

文字列リテラルは配列型のリテラルであり、Cでは、左辺値として以外に配列型が式に存在する方法はありません。文字列リテラルは、文字列「contents」を指すポインタ型(通常はポインタに減衰する配列型ではなく)を持つように指定できますが、これではあまり有用ではありません。特に、sizeof演算子はそれらに適用できませんでした。

C99では、左辺値でもある複合リテラルが導入されたため、リテラルを左辺値にすることは、もはや特別な例外ではないことに注意してください。それは標準に近いです。

31
R..

文字列リテラルはarrays-本質的に予測できないサイズのオブジェクト(つまり、ユーザー定義の、場合によっては大きなサイズ)です。一般的な場合、メモリ内のオブジェクト、つまりlvaluesとして以外に、このようなリテラルを表す方法は他にありません。 C99では、これは複合リテラルにも適用されます。これもlvaluesです。

文字列リテラルが言語レベルでlvaluesであるという事実を人為的に隠そうとすると、ポインタで文字列リテラルを指す機能とアクセス機能があるため、かなりの数の完全に不要な問題が発生します。配列としてのそれは、言語レベルで見えるその左辺値に決定的に依存しています。

一方、スカラー型のリテラルのコンパイル時サイズは固定されています。同時に、そのようなリテラルは、特定のハードウェアアーキテクチャ上のマシンコマンドに直接埋め込まれる可能性が非常に高くなります。たとえば、i = i * 5 + 2のようなものを書くと、リテラル値52は、生成されたマシンコードの明示的な(または暗黙的な)部分になります。それらは存在せず、データストレージ内のスタンドアロンの場所として存在する必要はありません。値52をデータメモリに保存しても意味がありません。

また、多くの(ほとんどまたはすべてではないにしても)ハードウェアアーキテクチャでは、浮動小数点リテラルが実際には「非表示」lvaluesとして実装されていることにも注意してください(言語ではそのように公開されていませんが)。 x86のようなプラットフォームでは、浮動小数点グループからのマシンコマンドは、埋め込まれた即値オペランドをサポートしていません。これは、事実上すべての浮動小数点リテラルをコンパイラがデータメモリに格納(およびデータメモリから読み取る)する必要があることを意味します。例えば。 i = i * 5.5 + 2.1のようなものを書くと、次のようなものに変換されます。

const double unnamed_double_5_5 = 5.5;
const double unnamed_double_2_1 = 2.1;
i = i * unnamed_double_5_5 + unnamed_double_2_1;

言い換えると、floating-point literalsは内部的に「非公式」lvaluesになることがよくあります。ただし、言語仕様がこの実装の詳細を公開しようと試みなかったことは完全に理にかなっています。言語レベルでは、arithmetic literalsrvaluesとしてより意味があります。

12
AnT

C++のlvalueは、必ずしもオブジェクトを参照するとは限りません。関数を参照することもできます。さらに、オブジェクトはlvaluesによって参照される必要はありません。それらは、配列(C++およびC)を含め、rvaluesによって参照される場合があります。ただし、古いC89では、配列からポインタへの変換はrvalues配列には適用されませんでした。

現在、rvalueは、有効期限が切れている、制限されている、または間もなく期限切れになることを示します。ただし、文字列リテラルはプログラム全体で使用できます。

そう string literalslvaluesであることは正確に正しいです。

元々の動機は主に実用的な動機だったと思います。文字列リテラルはメモリ内に存在し、アドレスを持っている必要があります。文字列リテラルの型は配列型(char[] Cでは、char const[] in C++)、および配列型はほとんどのコンテキストでポインターに変換されます。言語はこれを定義する他の方法を見つけることができたかもしれません(例えば、文字列リテラルはそれが指しているものに関する特別な規則で、最初にポインタ型を持つことができます)が、リテラルを左辺値にすることはおそらく具体的に何を定義する最も簡単な方法です必要です。

6
James Kanze