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

Why are string literals l-value while all other literals are r-value?

本文关键字:文字 其他 字符串 为什么      更新时间:2023-10-16

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

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

类似地,C99 6.5.1§4说:

字符串文字是主要表达式。它是一个类型如6.4.5所述的左值。

这背后的理由是什么?

据我所知,字符串文字是对象,而所有其他文字都不是。l值总是指一个对象。

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

我知道这个问题的答案可能与硬件架构有关,而不是与C/C++作为编程语言有关,尽管如此,我还是希望听到同样的答案。

字符串文字是具有数组类型的文字,在C中,数组类型除了作为左值之外,不可能存在于表达式中。字符串文本可以被指定为具有指向字符串"contents"的指针类型(而不是通常衰减为指针的数组类型),但这会使它们用处不大;特别是sizeof运算符不能应用于它们。

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

字符串文字是数组-具有固有不可预测大小的对象(即用户定义的,可能是大大小的)。在一般情况下,除了作为内存中的对象(即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更有意义。

我猜最初的动机主要是一个务实的动机:字符串文字必须存在于内存中并具有地址。字符串的类型literal是一种数组类型(在C中为char[],在C++中为char const[]),并且在大多数上下文中,数组类型转换为指针。语言可以已经找到了其他方法来定义它(例如,字符串文字可能指针类型,带有关于它的特殊规则指向),但仅仅使文字成为左值可能是定义具体需要什么的最简单方法。

C++中的lvalue并不总是引用对象。它也可以指函数。此外,对象不必由lvalues引用。它们可以由rvalues引用,包括用于数组(在C++和C中)。然而,在旧的C89中,数组到指针的转换不适用于rvalues数组。

现在,rvalue表示没有、有限或即将过期的寿命。然而,字符串文字适用于整个程序。

所以string literals就是lvalues是完全正确的。

答案和评论中有很多有价值的信息。有几点值得强调。

数组可以是右值。更多信息可以在这里和这里找到。例如,以下代码涉及一个右值数组:

template <typename T>
using alias = T;
int main() {
    return alias<int[]>{23, 37, 53}[1];
}

因此,将字符串文字作为数组并使其成为lvalue是不好的。

最好记住字符串文字在程序的整个生命周期中都是有效的。尽管值类别不是生存期,但理解为什么字符串文字是基于其生存期的lvalue是有意义的。

就像许多关于值类别的讨论一样,字符串文字是lvalue在很大程度上是由语用考虑驱动的,即到目前为止在语言发展中发生了什么,以及从我们当时的立场来看,什么是最好的。