为什么这段代码没有结果y == 0x100
?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
在这里自己检查一下:http: //codepad.org/dmsmrtsg
为什么这段代码没有结果y == 0x100
?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
在这里自己检查一下:http: //codepad.org/dmsmrtsg
从 C 语言的角度来看,您发布的代码是无效的。C 中任何强制转换的结果都是右值。它不能用作 的参数++
。运算符++
需要一个左值参数。ie 表达式++((unsigned) x)
在标准 C 语言中是不可编译的。
在这种情况下,您实际观察到的是 GCC 的“广义左值”扩展
http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Lvalues.html
根据该扩展(并且与标准 C 相反),应用于左值的强制转换会产生左值。当您尝试将某些内容写入生成的“通用”左值时,正在写入的值将被转换两次:首先将其转换为显式转换指定的类型,然后将中间结果再次转换为接收对象的类型。最终结果被放入接收者对象中。
例如,如果和x
你一起做
(unsigned) x = 0x100;
它实际上会被 GCC 解释为
x = (uint8_t) (unsigned) 0x100;
最终值为x
will 0
。
这正是您的示例中发生的情况。在 GCC 你的
++((unsigned) x)
相当于
(unsigned) x = (unsigned) x + 1;
这反过来又被 GCC 解释为
x = (uint8_t) (unsigned) ((unsigned) x + 1);
这就是为什么你作为结果0
进入x
的原因,这就是0
然后被分配给你的y
.
此扩展被GCC 文档称为已弃用。
首先,这不是有效的 C 代码,我不知道您是如何编译它的,但是您的链接确实显示了输出,因此我将尝试根据这一主要假设来解释发生了什么:
我猜这行代码unsigned y = ++((unsigned x));
会unsigned
被你的编译器删除,这就是为什么你能够构建的原因。
所以,假设...
uint8_t x = 0xff; // 8 bit value, max is 255(10) or 0xFF(16)
unsigned y = ++((unsigned)x);
现在x
已经具有其类型的最大值。你想知道为什么如果我们通过 +1 ++
,y
不会得到0x100
.
x
是 8 位,类型转换它不会改变它是 8 位的事实。所以当我们说:
++x
我们正在递增x
( x=x+1
)。所以我们有一个无符号的 8 位值,最大值并加 1,现在它被环绕为 0。所以y
会得到 0。
如果你想让这个工作,你可以做类似的事情:
int main(void)
{
unsigned char x = 0xFF; //I'm using char because it's 8 bit too
unsigned int y = 1+x; //no need to typecast, we're already unsigned
printf("%#x %#x\n", x, y);
return 0;
}
现在您将获得预期值 (x==0xFF
和y==0x100
)
试试这个:
uint8_t x = 0xff;
unsigned y = ((unsigned)x) + 1;
它会如你所料,因为(unsigned) x
现在是两字节值0x0100
。
现在试试这个:
uint8_t x = 0xff;
++x;
的值0xff
环绕到0x00
。
我在你的摘录中加入了一些小的透明代码,它解释了一切。
#include <stdio.h>
#include <stdint.h> // not needed
int main(void) {
uint8_t x = 0xff;
printf("%d\n", sizeof(x));
unsigned y = ++((unsigned)x);
printf("%d\n", sizeof(y));
printf("0x%x\n", y);
printf("%d\n", sizeof(y));
return 0;
}
输出是
1 // size of x
4 // size of y before computation
0x100 // computed value of y from your code
4 // size of y after computation
首先要注意的是在sizeof(y)
整个计算过程中保持不变。
从输出来看,
uint8_t
= 1 个字节unsigned
= 4 个字节当您在 C 中进行强制转换时,将其视为隐式调用realloc
:“从其块中获取我拥有的这些数据,将其在内存中的大小增加(或减少)到我想要将其转换为的大小,然后返回新块中的相同数据。
从我们的尺寸来看,unsigned
将有足够的空间来适应单字节操作的计算结果。
以字节级别的细节重新解释您的代码,
x = 11111111 = 0xff (in a byte)
(unsigned)x = 00000000000000000000000011111111 = 0xff (in a word)
++((unsigned)x) = 00000000000000000000000100000000 = 0x100