C 为什么不是';这难道不是左倾的结果吗?

C 为什么不是';这难道不是左倾的结果吗?,c,casting,lvalue,rvalue,C,Casting,Lvalue,Rvalue,我需要一些关于这种奇怪行为的建议——让我们来看看下面的代码: int ** p; 这可以毫无困难地编译: p++; 但这是: ((int**)p)++; 给我这个错误消息:“错误:需要左值作为增量操作数” 我正在将p转换为它已经是的类型,没有任何变化,那么问题是什么?这是我在试图编译一个旧版本时遇到的问题的简化版本 gdb的版本。所以我想,这起作用了,有些东西改变了。你知道第二个例子有什么问题吗 当您键入表达式时,该表达式的结果是右值而不是左值。直观地说,typecast会说“给我这个表达

我需要一些关于这种奇怪行为的建议——让我们来看看下面的代码:

int ** p;
这可以毫无困难地编译:

p++;
但这是:

((int**)p)++;
给我这个错误消息:
“错误:需要左值作为增量操作数”

我正在将
p
转换为它已经是的类型,没有任何变化,那么问题是什么?这是我在试图编译一个旧版本时遇到的问题的简化版本
gdb的版本
。所以我想,这起作用了,有些东西改变了。你知道第二个例子有什么问题吗

当您键入表达式时,该表达式的结果是右值而不是左值。直观地说,typecast会说“给我这个表达式如果有其他类型的话会有的值”,所以将变量类型转换为它自己的类型仍然会产生右值而不是左值。因此,将
++
运算符应用于类型转换的结果是不合法的,因为
++
需要左值,而您提供的是右值

也就是说,原则上可以重新定义C语言,以便在原始表达式是左值的情况下,将值强制转换为其自己的类型产生左值,但出于简单性和一致性的考虑,我认为语言设计者没有这样做


希望这有帮助

gcc的旧版本支持所谓的“左值强制转换”——如果您强制转换某个左值,那么结果就是左值,可以这样处理。它的主要用途是允许您将指针增加与不同大小相对应的量:

int *p;
++(char *)p;  /* increment p by one byte, resulting in an unaligned pointer */
这个扩展在gcc v3.0前后被弃用了一段时间,并在gcc v4.0中被删除

要在较新版本的gcc中执行类似的操作,您需要执行一个加法和赋值(而不是增量),将指针转换为加法类型,并返回赋值类型:

p = (int *)((char *)p + 1);

请注意,在这之后尝试取消引用指针是未定义的行为,因此不要指望它做任何有用的事情。

在C语言中,所有转换(包括显式转换)都会生成右值。没有例外。您将其强制转换为同一类型的事实并不能使其免于遵守该规则。(事实上,期望它做出如此不一致的例外是很奇怪的。)

事实上,整个C语言的一个基本特性是它总是尽可能快地将表达式中的左值转换为右值。C表达式中的左值类似于门捷列夫表中的第115个元素:它们通常寿命很短,很快衰减为右值。这是C和C++之间的主要区别,后者总是试图尽可能长地保存表达式中的LValk(尽管在C++中,这个特定的转换也会产生一个R值)。 为什么这个结果不是左倾的

我提请您注意C99规范第6.5.4节第4行脚注86,其中规定:

铸型不会产生左值

你有演员阵容

结果不是左值

++
运算符需要左值


因此,您的程序是一个错误。

“无变化”-事实上,许多事情都会发生变化,其中之一是强制转换表达式的结果不是左值而是右值(它不指定存储),因此增加它是没有意义的。是的。“如果你那样做会受伤,也许你不应该那样做。”演员阵容的结果从来都不是左值。从gdb的旧版本中看到确切的代码会很有趣;我怀疑你的简化隐藏了实际问题。IIRC某些版本的VC++允许这样做(可能是VC++7.1)。我很难想象
gbd
实际使用了这样的东西。就像碳酸指出的那样,这完全是错误的。这个术语是“铸造”,而不是“铸型”。(类型转换是演员的事情。)@KeithThompson我见过“类型转换”这个词被广泛使用,而“类型转换”只是它的一个短期术语。似乎也支持这一点。术语“typecast”在K&R2或ISO C标准中没有出现过(在那篇维基百科文章中只出现过一次,它将显式C类型转换称为“Cast”)。顺便说一句,我刚刚编辑了维基百科页面,但我没有触及“typecasting”的引用。@KeithThompson我怀疑用C/C++的说法,术语是“cast”,而在更广泛的CS上下文中,术语是“typecast”。这可以解释一些事情。:-)所以,如果你想铸造一些东西,然后用它作为左值,有什么办法吗?我可以考虑将右值分配给一个适当声明的指针——这是一个好方法,还有更好的方法吗?@PhilPerry:因为我们不知道您的实际目标是什么,所以很难告诉您如何更好地实现它。你可能不是为了自己的利益而试图从演员阵容中获得左值;你有更大的目标。通过强制转换并期望得到一个左值是无法达到这个目的的,所以与其继续沿着这条错误的道路走下去,不如描述一下你真正的问题并寻求帮助来解决它。@Phil Perry:将某个东西作为不同类型的左值,实际上并不是一种类型转换,而是一种原始内存的重新解释。在C语言中,原始内存的重新解释是通过向上提升一级间接寻址(使用
&
运算符),在那里执行强制转换,然后使用
*
运算符返回到原始级别来实现的。在OP的例子中,它看起来如下:
(*(int***)和p)++//code>。当然,这个例子有纯粹的学术价值,因为
p
已经是
int**
@Eric了,我手头没有具体的问题要解决。只是@AndreyT的回答引发了这样一种想法:在未来的某个时候,我可能想投射,比如说,一个指向其他东西的指针,并将其用作左值,如何才能做到最好?比如说,我有一个
void*
数组,我想递增到下一个整数o