C 意外的++;((未签名)x),x是uint8_t?

C 意外的++;((未签名)x),x是uint8_t?,c,gcc,C,Gcc,为什么这段代码不会导致y==0x100 uint8_t x = 0xff; unsigned y = ++((unsigned)x); 请在此处亲自查看:从C语言的角度来看,您发布的代码是无效的。C中任何强制转换的结果都是右值。它不能用作++的参数。运算符++需要左值参数。也就是说,表达式++((无符号)x)在标准C语言中是不可编译的 在本例中,您实际观察到的是GCC的“广义左值”扩展 根据该扩展(与标准C相反),应用于左值的转换生成左值。当您尝试将某些内容写入结果“广义”左值时,所写入的值

为什么这段代码不会导致
y==0x100

uint8_t x = 0xff;
unsigned y = ++((unsigned)x);

请在此处亲自查看:

从C语言的角度来看,您发布的代码是无效的。C中任何强制转换的结果都是右值。它不能用作
++
的参数。运算符
++
需要左值参数。也就是说,表达式
++((无符号)x)
在标准C语言中是不可编译的

在本例中,您实际观察到的是GCC的“广义左值”扩展

根据该扩展(与标准C相反),应用于左值的转换生成左值。当您尝试将某些内容写入结果“广义”左值时,所写入的值将被转换两次:首先将其转换为显式转换指定的类型,然后将中间结果再次转换为接收方对象的类型。最终结果将放入收件人对象中

例如,如果使用
x
您可以

(unsigned) x = 0x100;
GCC实际上会将其解释为

x = (uint8_t) (unsigned) 0x100;
x = (uint8_t) (unsigned) ((unsigned) x + 1);
x
的最终值将为
0

这就是你的例子中发生的事情。在你的

++((unsigned) x)
相当于

(unsigned) x = (unsigned) x + 1;
GCC将其解释为:

x = (uint8_t) (unsigned) 0x100;
x = (uint8_t) (unsigned) ((unsigned) x + 1);
这就是为什么在
x
中得到
0
作为结果,这就是
0
然后分配给
y
的原因


GCC文档称此扩展已弃用。

从C语言的角度来看,您发布的代码无效。C中任何强制转换的结果都是右值。它不能用作
++
的参数。运算符
++
需要左值参数。也就是说,表达式
++((无符号)x)
在标准C语言中是不可编译的

在本例中,您实际观察到的是GCC的“广义左值”扩展

根据该扩展(与标准C相反),应用于左值的转换生成左值。当您尝试将某些内容写入结果“广义”左值时,所写入的值将被转换两次:首先将其转换为显式转换指定的类型,然后将中间结果再次转换为接收方对象的类型。最终结果将放入收件人对象中

例如,如果使用
x
您可以

(unsigned) x = 0x100;
GCC实际上会将其解释为

x = (uint8_t) (unsigned) 0x100;
x = (uint8_t) (unsigned) ((unsigned) x + 1);
x
的最终值将为
0

这就是你的例子中发生的事情。在你的

++((unsigned) x)
相当于

(unsigned) x = (unsigned) x + 1;
GCC将其解释为:

x = (uint8_t) (unsigned) 0x100;
x = (uint8_t) (unsigned) ((unsigned) x + 1);
这就是为什么在
x
中得到
0
作为结果,这就是
0
然后分配给
y
的原因


GCC文档将此扩展称为不推荐使用的扩展。

首先,这是无效的C代码,我不知道您是如何编译它的,但您的链接确实显示了一个输出,因此我将尝试根据这一假设解释发生了什么


我猜这一行
无符号y=++((无符号x))编译器正在删除第二个
未签名的
,因此您可以构建


所以,假设

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

开始这是无效的C代码,我不知道您是如何编译它的,但您的链接确实显示了一个输出,因此我将尝试根据这一假设解释发生了什么:


我猜这一行
无符号y=++((无符号x))编译器正在删除第二个
未签名的
,因此您可以构建


所以,假设

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

尝试以下操作:

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;
}
首先要注意的是,
sizeof(y)
在整个计算过程中保持不变。
从产出来看

  • uint8\u t
    =1字节
  • 无符号
    =4字节
在C中执行强制转换时,可以将其视为对
realloc
的隐式调用,其中说:“从其块中获取此数据,将其在内存中的大小增加(或减少)到我想要的大小