应用于左值或右值宽度的C二进制运算符

应用于左值或右值宽度的C二进制运算符,c,casting,binary,rvalue,C,Casting,Binary,Rvalue,C如何处理二进制运算符?标准要求编译器将其转换为左值还是不需要 我发现的具体问题如下: typedef union { unsigned long _Data; struct { unsigned long _Reserved : 28; unsigned long _Info : 1; unsigned long _Reserved2 : 3; }; } S_INFO; S_INFO Variable; 有了这些定义,指

C如何处理二进制运算符?标准要求编译器将其转换为左值还是不需要

我发现的具体问题如下:

typedef union {
  unsigned long _Data;
  struct {
    unsigned long  _Reserved    : 28;  
    unsigned long  _Info        : 1;
    unsigned long  _Reserved2   : 3;
  };
} S_INFO;

S_INFO Variable;
有了这些定义,指令

Variable._Data &= ~3uL;
Variable._Data &= ~3u;
Variable._Data &= ~3uL;
编译与指令不同的代码

Variable._Data &= ~3uL;
Variable._Data &= ~3u;
Variable._Data &= ~3uL;
在目前的16位体系结构中,int是2字节宽,long是4字节宽

编译器似乎将&运算符应用于文本的宽度(右值),而不是左值变量的宽度


我是否发现了一个编译器错误,或者根据C标准,这是正确的行为?

在等待您发布关于两段代码如何编译不同的发现时(由于我的评论似乎促使您考虑一个答案,但我不确定这是正确的答案,)我只想说,可能发生的情况是:

指令
变量。_Data&=~3uL导致无符号长文字与长值进行AND运算

指令
变量。_Data&=~3u接受一个无符号(非长)文本,零将其扩展为长,然后用长值与之和

因此,这些指令的编译方式不同,很可能是由于在正确的操作数中声明文字的方式不同。这可能与左操作数无关,也与在操作数之间执行的操作无关


无论如何,在这一点上,这是我的猜测;请发表您的发现,说明这两段代码的编译方式不同,我可能会修改我的答案。

等待您发表您的发现,说明这两段代码的编译方式不同,(由于我的评论似乎促使你思考一个答案,但我不确定这是否是正确的答案,)让我说,可能发生的情况是:

指令
变量。_Data&=~3uL;
导致无符号长文字与长值进行AND运算

指令
变量。_Data&=~3u;
采用无符号(非长)文本,零将其扩展为长,然后用长值与之和

因此,这些指令的编译方式不同,很可能是因为您在右操作数中声明文字的方式不同。这可能与左操作数无关,也与您在操作数之间执行的操作无关


无论如何,在这一点上,这是我的猜测;请发表您的发现,确切地说这两段代码是如何编译成不同的,我可以修改我的答案。

这不是一个错误,这两个表达式不相等:

两者都会将最低有效的两位置零。但只有第二位会将最高有效的16位置零。请记住,在您的计算机上,int类型的宽度为16位,长宽度为32位

在执行
&=
操作之前,一元
~
运算符将应用于整数文本。差异(在您的机器上)为:

操作~3LU的结果为:0xFFFFFFFC

操作~3U产生:0xFFFC,然后升级为长:0x0000FFFC

将这两个值应用于
变量。_Data
的结果如上所述不同

第一个是:

Variable._Data &= 0xFFFFFFFC;
第二个是:

Variable._Data &= 0x0000FFFC;

这不是错误,这两个表达式不相等:

两者都会将最低有效的两位置零。但只有第二位会将最高有效的16位置零。请记住,在您的计算机上,int类型的宽度为16位,长宽度为32位

在执行
&=
操作之前,一元
~
运算符将应用于整数文本。差异(在您的机器上)为:

操作~3LU的结果为:0xFFFFFFFC

操作~3U产生:0xFFFC,然后升级为长:0x0000FFFC

将这两个值应用于
变量。_Data
的结果如上所述不同

第一个是:

Variable._Data &= 0xFFFFFFFC;
第二个是:

Variable._Data &= 0x0000FFFC;


附加信息:第二条指令清除变量的前16位。_Data.name以下划线加大写字母开头是为实现保留的,永远不要使用它们!(不过,您可以使用小写,这在C中对于成员来说也更常见)。拿笔和纸,写下两个常量的位模式。然后手动处理这些模式上的表达式。谢谢你的回答。你说“保留用于实现”是什么意思?它们是为实现保留的。对此有什么不清楚的?参见标准7.1.3附加信息:第二条指令清除变量的前16位。\u数据。以下划线加大写字母开头的名称是为实现保留的,永远不要使用它们!(你可以使用小写,这在C语言中对成员来说更为常见)。获取笔和纸,并写下两个常量的位模式。然后手动处理这些模式上的表达式。谢谢你的回答。“保留用于实现”是什么意思?它们是为实现保留的。对此有什么不清楚的吗?请参阅标准7.1.3附加信息:第二条指令清除变量的前16位。\u Data.噢,我错过了。编辑旧注释的时间太短了……对不起,我是这个平台的新手。谢谢你的回答。这基本上是我假设的“编译器可能会执行强制转换,但仅在二进制文件之后才执行强制转换。”。关于您的答案,我查看了反汇编。结果如“附加信息:第二条指令清除变量的前16位。\u数据”中所述。“。这基本上也是您现在假设的。顺便说一句,我也在上重现了问题。随着不同操作的分离,问题变得更加全面。@尾码请参阅我的答案以了解详细信息。其他信息:第二条指令清除了前16位o