【发布时间】:2018-01-29 03:03:49
【问题描述】:
1U printf("%u\n", 1U << 32),编译器会将结果优化为0。但是当我尝试这段代码时,
#include <stdio.h>
int main() {
int n = 32;
printf("%u\n", 1U << n);
}
编译执行上面的代码会打印出1的结果。
根据C/C++标准,
E1的值
在我看来,当E1无符号并且E1
但是在 x86 和 ARM 上使用 GCC 4.4 到 7.2 或 Clang 3.1 到 5.0 编译结果为 1。我检查了汇编代码,发现两者都产生了以下汇编,
movl $20,-0x4(%rbp)
mov -0x4(%rbp),%eax
mov $0x1,%edx
mov %eax,%ecx
shl %cl,%edx
和
orr w8, wzr, #0x1
orr w9, wzr, #0x20
stur w9, [x29, #-4]
ldur w9, [x29, #-4]
lsl w1, w8, w9
然后我检查了shl 和lsl 的指令,在c9x.me 上我发现以下关于shl 的描述,
目标操作数可以是寄存器或内存位置。计数操作数可以是立即数或寄存器 CL。计数被屏蔽为 5 位,这将计数范围限制为 0 到 31。
ARM 的汇编程序指南告诉lsl 允许的移位是 0-31。
这意味着至少指令shl运行良好,这就是为什么我怀疑编译器的实现是错误的,但似乎不可能有这么长时间的这样一个错误,谁能给我解释一下?
谢谢。
【问题讨论】:
-
首先,对于语义规则,您应该只指定一种语言。 C 和 C++ 是两种非常不同的语言。他们的标准也非常不同,即使是类似的事情也有不同的措辞。
-
"ARM 的汇编指南告诉我们,lsl 允许的移位是 0-31",而"计数被屏蔽为 5 位"意味着你的 32 变成了 0,所以不执行移位。
-
<stdio>既不是 C 也不是 C++。可能是我一直听说的这种新的“C/C++”语言。 -
但是您确实引用了“C/C++ 标准”。找到这份超级机密文件了吗?
标签: c