为什么“地址”表达式不是左值?

问题描述 投票:0回答:1

C 标准将 lvalue 定义为:

左值是一个可能指定对象的表达式(具有除 void 之外的对象类型);64) 如果左值在求值时未指定对象,则行为未定义。当一个对象被认为具有特定类型时,该类型由用于指定该对象的左值指定。可修改左值是不具有数组类型、不具有不完整类型、不具有 const 限定类型的左值,并且如果它是结构体或联合,则不具有任何成员(递归地包括任何成员)或所有包含的聚合或联合的元素)具有 const 限定类型。

我想准确理解该定义的哪一部分阻止“地址”表达式(例如

&ch
)成为左值。当我们获取一个对象的地址时,该地址不是“指定”该对象吗(因此,如果我们有
char ch
,那么
&ch = 10
将相当于
ch = 10
)?或者
&ch
指定临时的,而不是对象? (有没有临时物体之类的东西?)

我的困惑最初是在阅读C 上的指针时产生的,其中提供了以下解释:

优先级表显示

&
运算符产生 R 值作为结果,并且它们不能用作 L 值。但为什么?答案很简单。当计算表达式
&ch
时,结果保存在计算机中的哪里?它一定在某个地方,但你无法知道在哪里。 该表达式不识别机器内存中的任何特定位置,因此不是左值。

我对粗体部分感到困惑。

&ch
不知道
ch
的位置吗?

c pointers language-lawyer memory-address
1个回答
0
投票

显然&ch

contents
确实代表了机器内存中的一个特定位置,即
ch
的地址。这本书的意思可能是,临时结果
&ch
本身可能存储在寄存器等中,并且仅根据 C 代码我们无法知道在哪里。它实际上也不是
ch
的地址,而是该地址的副本。

示例:

int x = 1;
int* ptr = &x;
printf("%p\n", ptr);

这会产生以下汇编程序(gcc 14 x86):

lea     rsi, [rsp+12]
mov     DWORD PTR [rsp+12], 1
call    printf

即:将分配

x
的堆栈地址存储在寄存器
rsi
内。将值 1 移至堆栈上的该位置。

现在,如果我们以某种方式在这里注入一些内联汇编程序并写入寄存器

rsi
,它就不会影响
x
实际存储的位置。


一般来说,我们不希望程序员更改变量的地址,因为这会改变编译器和链接器的整个工作方式。如果需要的话,编译器会为每个变量提供一个地址(并且未放置在寄存器中),并且根据该地址,编译器可以推断出特定地址中存储的内容并相应地生成代码。如果我们想要更改变量的存储位置,我们通常通过将内容复制到新的地址位置来实现。

因此,变量的地址被视为只读,并且仅出于这个原因,

&
运算符就必须产生“右值”。我们通常不会在运行时更改存储地址,只是使用指针指向内存中的其他位置。

还值得注意的是

&
*
运算符的作用彼此相反。
*&x
相当于
x
,因为运算符相互抵消。
&
始终产生右值,但
*
始终产生左值。同样,
&*ptr
等价于
ptr
,但它是一个右值。

© www.soinside.com 2019 - 2024. All rights reserved.