为什么字符串文字是l值,而所有其他文字都是r值?

Alo*_*ave 53 c c++ literals string-literals

C++ 03 5.1主要表达式
§2:

文字是主要表达方式.它的类型取决于它的形式(2.13).字符串文字是左值; 所有其他文字都是右值.

这背后的理由是什么?
据我所知,字符串文字是对象,而所有其他文字都不是.并且l值总是指对象.

但问题是为什么字符串文字是对象,而所有其他文字都不是?
这个理由在我看来更像是鸡蛋或鸡肉问题.

我理解这个问题的答案可能与硬件架构有关,而不是C/C++作为编程语言,但我想听到同样的看法.

注意:我将此问题标记为c&c ++,因为C99标准也有类似的引用,特别是§6.5.1.4

R..*_*R.. 31

字符串文字是具有数组类型的文字,在C中,除了作为左值之外,表达式中无法存在数组类型.字符串文字可以被指定为具有指向字符串"contents"的指针类型(而不是通常衰减到指针的数组类型),但这会使它们变得不那么有用; 特别是,sizeof操作员无法应用于他们.

请注意,C99引入了复合文字,它也是左值,因此将文字作为左值不再是特殊的例外; 它更接近于常态.

  • 文字不能没有左值的数组类型,因为数组衰减到指针的方式.如果它没有对象类型,则它的初始元素的地址将不会衰减.正如我的(略微修改的)答案所述,语言*可以设计为*使得字符串文字*最初是指针类型的*,没有任何衰减,然后它们不需要是左值.但是在实践中这将没那么有用. (10认同)
  • `"你好"`不是右值.它是一个左值数组,它衰减为指向类型指针的表达式. (4认同)
  • `puts("hello")`是一个类型为`int`的表达式. (2认同)
  • 可以有rvalue数组类型 - 例如,如果你有`struct x {int a [2]; }; struct x foo(void);`then`foo().a`是一个右值数组.另外,给定`struct x bar,quux;`然后`(1?bar:quux).a`是一个右值数组. (2认同)
  • @R ..您能在下面对我的回答发表评论吗?似乎有很强的观点认为我不正确,但是我认为这可能是C和C ++有所不同的地方。我想在删除答案之前先检查一下:) (2认同)
  • @caf是正确的,因为`struct`返回值,有数组"rvalues"(或只是普通值).尽管如此,该标准在描述人们可以做些什么方面相当薄弱.实现中的一个大问题是它们可能(或可能不)存储在寄存器中(对于足够小的结构)或类似的"短暂"存储,并且数组操作 - 甚至像下标提取一个元素一样简单 - 可以覆盖此存储; 但是"普通"数组访问需要一个指向数组基础的相当持久的指针.指针有效多长时间?谁知道! (2认同)

AnT*_*AnT 12

字符串文字是数组 - 具有固有不可预测大小的对象(即用户定义的和可能大的大小).在一般情况下,除了作为内存中的对象,即没有其他方式来表示这样的文字lvalues.在C99中,这也适用于复合文字,也是lvalues.

任何试图人为地隐藏字符串文字lvalues处于语言级别这一事实的尝试都会产生相当多的完全不必要的困难,因为指向具有指针的字符串文字的能力以及作为数组访问它的能力依赖于它的左值在语言层面是可见的.

同时,标量类型的文字具有固定的编译时大小.同时,这些文字很可能直接嵌入到给定硬件体系结构的机器命令中.例如,当您编写类似i = i * 5 + 2文字值的内容5并2成为生成的机器代码的显式(甚至隐式)部分时.它们不存在,不需要作为数据存储中的独立位置存在.存储值5和2数据存储器毫无意义.

值得注意的是,在许多(如果不是大多数或全部)硬件体系结构中,浮点文字实际上实现为"隐藏" 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;
Run Code Online (Sandbox Code Playgroud)

换句话说,floating-point literals往往最终在lvalues内部成为"非正式的" .但是,语言规范没有尝试公开此实现细节,这是完全合理的.在语言层面,arithmetic literals更有意义rvalues.

  • 有趣的事实:x * 2.0通常会编译为x + x。这确实强调了“隐藏的左值”实际上只是一个asm实现细节,而不是基本的甚至与语言规则无关。事实更多,但值得指出。(尽管按条件规则甚至允许编译器修改字符串文字,例如将printf(“ hello \ n”)转换为puts(“ hello”)。) (2认同)

Joh*_*itb 9

一个lvalue在C++中并不总是指代对象.它也可以指一个功能.而且,不必参考对象lvalues.它们可以被引用rvalues,包括用于数组(在C++和C中).但是,在旧的C89中,数组到指针的转换不适用于rvalues数组.

现在,a rvalue表示不,有限或很快就会过期.但是,字符串文字适用于整个程序.

所以string literals存在lvalues是完全正确的.

  • 整数文字不引用对象,因此不需要考虑生命周期. (3认同)

Jam*_*nze 6

我猜这个原始动机主要是一个实用的动词:一个字符串文字必须驻留在内存中并且有一个地址.字符串文字的类型是数组类型(char[]在C中,char const[]在C++中),并且数组类型在大多数上下文中转换为指针.语言可以找到其他方法来定义它(例如,字符串文字可以有指针类型开头,有关于它所指向的特殊规则),但只是使文字成为左值可能是定义具体内容的最简单方法.需要.