【发布时间】:2020-09-12 23:40:28
【问题描述】:
我读到here,有符号运算有不同的算术汇编指令。但是考虑代码:
unsigned char a = 0xff;
if(a == 0xff){
// do something
}
我记得在拼贴中我编写了这样的代码,if 条件从来都不是真的,但它是在 AVR 上的。我在我的工作中看到过类似的东西,所以我把它输入到了godbolt,它显示了x86:
mov BYTE PTR [rbp-1], -1
cmp BYTE PTR [rbp-1], -1
jne .L2
这是令人不安的,因为它表明,无符号修饰符被忽略。它是否受标准和 gcc 监管,只是为了优化目的而简化,实际上将 0xff 转换为无符号?
编辑:我最初的问题有些混乱(我没有提到我的示例是针对 8 位处理器的)所以这里有一个替代方案:
int main(){
unsigned int a = 0xffffffff;
if(a == -1)
return 0;
return 1;
}
翻译为:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], -1
cmp DWORD PTR [rbp-4], -1
jne .L2
mov eax, 0
jmp .L3
.L2:
mov eax, 1
.L3:
pop rbp
ret
这(如果我理解正确的话)意味着 2^32-1 实际上等于 -1。
【问题讨论】:
-
不忽略无符号修饰符。您希望得到哪些指令而不是这些指令?
-
unsigned char a = 0xff;之后a的值是255。0xff的值也是255。即使有转换,当255转换为unsigned char或到int或unsigned int,值仍然是255。所以编译器会将255 与255 进行比较。你认为应该发生什么不同? -
你在 college 所做的可能是使用了
char,这是一个签名类型。 -
我希望看到:
movzx eax, BYTE PTR [rbp-1] cmp eax, -1 -
但是
0xff不是(int)-1。它是一个小的正整数。所以cmp eax, -1将实现 C 逻辑;这是错误的常数。但是,是的,movzx加载将显式实现 C 整数提升规则,即将该操作数的值保持扩大到==到int,匹配0xff的类型(作为数字文字默认为 int已经,不需要促销)。请注意,即使在 8 位处理器上,int也由 ISO C 保证至少为 16 位宽,并且0xff舒适地低于 INT_MAX。在优化扩展后,我们只能与-1进行字节比较。