首页 > 解决方案 > C 编译器如何确定有效的左值?

问题描述

我试图弄清楚 C 如何确定表达式是否是有效的 LVALUE。

我知道声明变量会给它一个命名的内存空间,这是变量名。变量名可以是 RVALUE 或 LVALUE。如果用于表示值,则使用其内容,但如果将其用作 LVALUE,则使用其地址来告知右侧的表达式存储在此地址中。我看到的这个操作的图片是这样ADDRESS=VALUE的:这就是赋值运算符的左右表达式的评估方式。

那么为什么我不能定义一个变量 like int a;,然后使用运算符的地址将值存储在该地址中,比如&a = 5;

我知道&a返回一个常量指针,但这意味着我不能更改地址或者我不能更改存储在地址中的值?如果它的内容不能改变,那为什么要使用*&a=5呢?

为什么我不能以这种方式赋值,尽管左手表达式总是被评估为我理解的地址?也许我的理解有问题?

标签: cpointersvariable-assignmentlvalue

解决方案


自动左值转换

C 2018 6.3.2.1 2 涵盖了这一点,其中说:

除非是运算符的操作数sizeof,一元&运算符,运算符,++运算--符,或运算符的左操作数.或赋值运算符,将不具有数组类型的左值转换为存储在指定对象中的值(并且不再是左值);这称为左值转换……</p>

考虑表达式x = y + z

  • y是 的操作数+。该+运算符不在上述例外列表中。所以y转换为它的值。
  • z是 的操作数+。该+运算符不在上述例外列表中。所以z转换为它的值。
  • x是 的左操作数=,即赋值运算符。这在上面的例外列表中。所以x仍然是一个左值。

关于&a = 5

关于int a;后跟&a = 5;

  • 运算符的结果&只是一个地址——它只是一个值;没有对象持有这个值,所以它不是左值。
  • 赋值运算符必须有一个左值作为其左操作数。C 2018 6.5.16 2 是一个约束,它表示“赋值运算符应有一个可修改的左值作为其左操作数。”</li>

因此&a = 5;违反了约束,需要 C 编译器为其生成诊断消息。=运算符不能将纯值作为其左操作数。

可以设计一种编程语言,以便赋值运算符接受&a = 5;并使用它将右侧的值存储在左侧给定的位置。BLISS 语言就是这样做的。在 BLISS 中,变量的名称总是提供它的地址。要获取该值,您必须在变量前面加上句点(其作用类似于 C 的一元运算*符)。所以你会写z = .x + .y. 因此,C 不这样做的事实是关于美学和便利性的选择,而不是关于逻辑必要性的选择。在 C 中,左值在大多数地方会自动转换为值,但对对象而不是值起作用的运算符除外。在 BLISS 中,您必须明确指定每个左值到值的转换。

关于*a = 5

*&a=5

  • 运算符根据*C 2018 6.5.3.2 4 生成一个左值:“一元运算*符表示间接。如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是一个指定该对象的左值……”</li>

因此*&a提供了赋值运算符所需的左值。


推荐阅读