C 将指针强制转换为左值
为什么C 将指针强制转换为左值,c,pointers,casting,rvalue,lvalue,C,Pointers,Casting,Rvalue,Lvalue,为什么(int*)p=&x不是有效的语句? 而*(int*)p=&x是没有警告的有效语句吗? 我知道casting是rvalue,但是第二条语句是如何编译的,没有任何警告 (int*) p = &x; 这是无效的,因为强制转换的结果不是左值。它只是一个类型为强制转换中指定类型的表达式 *(int*) p = &x; 这是有效的,因为解引用运算符*的结果是左值。取消对指针的引用将为您提供指针指向的对象。直观地说,左值是一个表示“这是一个诚实的对象”的表达式,而右值是一个表示“这
(int*)p=&x代码>不是有效的语句?
而*(int*)p=&x代码>是没有警告的有效语句吗?
我知道casting是rvalue,但是第二条语句是如何编译的,没有任何警告
(int*) p = &x;
这是无效的,因为强制转换的结果不是左值。它只是一个类型为强制转换中指定类型的表达式
*(int*) p = &x;
这是有效的,因为解引用运算符*
的结果是左值。取消对指针的引用将为您提供指针指向的对象。直观地说,左值是一个表示“这是一个诚实的对象”的表达式,而右值是一个表示“这是一个非对象的值”的表达式。(区别比这要模糊一些,但现在它是一个合理的简化。)也就是说,左值是可以放入某些内容的框,而右值只是框中的值
例如,表达式137
是一个右值,因为它是一个纯数字,而不是一个包含数字的框。如果x
是一个变量,则表达式x
是一个左值,因为它同时表示框和其中的数字,而表达式x+137
是一个右值,因为它只表示一个数字,而不是一个包含数字的框
你是如何理解这一点的?假设x
是一个int
。然后,(float)x
是一个右值,因为它纯粹代表一个值——具体地说,它是“如果你取了x
,并且做了尽可能不可怕的事情,将其表示为float
”它不是一个可以放东西进去的盒子
这就是原因
(int *)p = &x;
不起作用(int*)p
是一个右值-一个纯值,不是可以赋值的值-您试图将其视为可以放入的框
另一方面,指针解引用的结果是一个左值,因为它表示“看那边!这是一个可以放入内容的框。”因此,从这个意义上说,您可以编写
*(int *)p = x;
因为那意味着
计算表达式(int*)p
。好的,我们现在有一个右值,它是指向内存中某个地方的指针,其中包含int
取消引用该指针以获取*(int*)p
。好的,我们现在有一个左值,代表那个整数
把x
塞进那个地方。很好-*(int*)p
是一个方框
但是,此代码可能存在其他一些问题:
*(int *)p = &x;
这里,此表达式的RHS具有类型(int*)
,这是一个指针。此表达式的LHS的类型为int
(您取消了对整数的引用),因此您正在将指针转换为整数。这意味着要么是缺少了一个演员阵容,要么是你用这段代码做了错事
第二个问题是
*(int *)p
意思是“解释p
,就好像它告诉你在内存中的什么地方可以找到int
,然后在那里写一些东西。”如果p
不是指针,这几乎肯定会使你的代码崩溃,因为你会在内存中的某个地方随机写东西。如果p
是一个指针,那么最好使用&x
,而不是p
p = (T*) &x;
其中T
是p
所指的类型,技术术语有时会令人困惑,尤其是当读者不太了解事物的工作原理时
什么是左值?有地址的东西。
在第一种情况下,您有一个指针。在第二种情况下,取消对指针的引用
什么是指针?指针是地址。地址本身并没有地址(好吧,我们在这里不要太专业)。在您的示例中,假设p
是常数1235。它的地址是什么?没有,它只是一个常量,它可能不存在于内存中。也许在登记簿里。也许编译器完全优化了它。
此外,您的表达式是(int*)p=&x
表示“获取地址1235并将x的地址分配给它,它可能类似于6789”。换言之,“将地址1235更改为6789”。什么?!换个地址
什么是解引用指针?它是指针的内容,即指针指向的地址处的值。现在,根据定义,有了地址!这就是第二个声明中发生的事情。它的意思是“将p
指向的地址的内容设置为&x
”。因此,在我的示例中,它表示“将内存地址1235处的值设置为6789”。现在说得通了!这就是为什么它是左值
我希望这是有意义的。在第二种情况下,您有一个左值。您是如何声明x
?如何定义p
?我觉得那个代码很可疑。不知道涉及的类型就无法回答。。。尽管如此,这并没有阻止3个人回答代码>:D“如果p是指针,那么最好抛出&x,而不是p?”可能p是一个void*
指针(当然,抛开对&x
的所有正确怀疑)。