a/C编译器是否在编译时执行移位操作?

a/C编译器是否在编译时执行移位操作?,c,compiler-construction,bit-shift,C,Compiler Construction,Bit Shift,有人提到,编写良好的C编译器应该在编译时(即非运行时)执行移位运算符;例如,在此代码中,左移- 按照§6.5.7的规定,任何符合C标准的编译器将提供移位运算符。它们在使用整数表达式时不会出现问题(无论它们是否为常量)1) 但是,在对负整数使用它们时要小心,因为符号传播不是标准强制要求的(实际上,左移位操作数为负数是未定义的行为,而右移位是实现定义的)。此外,带符号整数的溢出行为尚未定义 1.如§6.5.7¨2所述,对操作数的唯一约束是 每个操作数应为整数类型 所有这些东西都不再相关,因为问题

有人提到,编写良好的C编译器应该在编译时(即非运行时)执行移位运算符;例如,在此代码中,左移-

按照§6.5.7的规定,任何符合C标准的编译器将提供移位运算符
。它们在使用整数表达式时不会出现问题(无论它们是否为常量)1)

但是,在对负整数使用它们时要小心,因为符号传播不是标准强制要求的(实际上,左移位操作数为负数是未定义的行为,而右移位是实现定义的)。此外,带符号整数的溢出行为尚未定义


1.如§6.5.7¨2所述,对操作数的唯一约束是

每个操作数应为整数类型


所有这些东西都不再相关,因为问题完全改变了


值得一提的是,当所有操作数都已知(并且启用了优化)时,编译器可以而且通常会在编译时执行计算。

每个C编译器都必须实现移位运算符,因为它们是语言的一部分。对j没有任何限制


编辑:因为您完全改变了问题:是的,要优化掉,当然j需要是编译时常量,否则,编译器在编译时应该如何知道它的值,但优化具有常量操作数的算术指令是优化代码时首先要做的事情之一。事实上,我认为,VC和gcc即使在没有激活优化级别的情况下也会这样做,这是显而易见的。

你到底在问什么?你的意思是“编译器会自己做移位吗”?如果你问的是这个问题,答案是“视情况而定”:。如果被移位的数字和移位的大小都是编译时常量,那么编译器几乎肯定会进行移位(尽管它不必这样做)。否则,它将生成执行转换的低级代码(通常是一条机器指令)。

编译器没有义务将您的程序、逐字(或您期望的方式)翻译成汇编或机器语言。编译器可以在语言标准的范围内自由翻译程序,只要行为相同。如果您的程序调用未定义的行为、特定于平台的行为或编译器定义的行为,则所有赌注都将被取消

编译器通常不会使用常量对移位进行编码。他们可以在编译过程中计算值,然后加载值。他们可能选择乘或除而不是移位

更智能的编译器可能会评估您的表达式,并使用更有效的公式生成答案。另一方面,编译器也可以消除答案未被使用的移位


我建议将注意力集中在程序的正确性和健壮性上,而不是担心编译器如何优化代码。在程序正常运行且健壮后,如果有额外的时间,或者程序的大小或执行速度不令人满意,请进行优化。

如果编译器可以在编译时确定操作数的值,并且在适当的优化级别调用它,则可能会在编译时执行该操作


将变量标记为
const
可能有助于编译器进行该确定。在某些情况下,编译器也可以通过数据流分析(例如:初始化为常量且从未修改过的局部变量等)自行进行转换。

编译器实现的移位示例如下(行为未定义):

#包括
内部主(空){
常数i=32;
printf(“%d%d\n”,1
有没有依赖于j是a
不变还是可变

当然有。编译器如何在编译时计算一个依赖于运行时才知道的操作数的结果


无论是谁向你“提及”这一点,要么是信息错误,要么没有说出你理解他们说的话。

所有内容都是为有符号整数类型中的正整数定义的吗?例如,会>>在高端变为零吗?简单回答=不要对位向量使用有符号类型,但出于好奇……对于
>
,是的,行为与无符号
类型相同。对于
类型,不确定对j没有约束。例如,如果j大于整数类型中的位数,结果不是未定义的吗?编译器不必实现这些操作;它们必须提供相同的功能。它们可以发出乘法指令,而不是移位。一个程序,只是给编译器的一组建议。至少没有约束j是常数之类的。@Thomas是的,但结果是定义的。当它们提供相同的功能时,它们正在实现它。但你是对的,它可能是,控制你的淋浴喷头的微控制器没有专用的换档装置uction!@Christian-不太可能。一些简单的处理器,你必须使用移位和加法来实现乘法,所以不会发生乘法-但是没有移位指令会非常奇怪。你可以为左移位本身添加一个值,但我想不出如何从其他基本指令实现右移位。除法是更可能的省略,除法算法需要右移,所以“除以(二的幂)”就是作弊。最后一段通常写为:“先做,然后做对,然后快速做”。将一个或多个变量声明为
const
,然后打印汇编语言列表,看看会发生什么。
constant unsigned int elements = length/8 + (length % y > 0 ? 1 : 0);  
unsigned char bit_arr[elements];
bit_arr[i] |= (1 << j); // Set 
bit_arr[i] &= ~(1 << j);  // Unset
if( bit_arr[i] & (1 << j) ) // Test
#include <stdio.h>

int main(void) {
    const int i = 32;
    printf("%d %d\n", 1 << 32, 1 << i);
    return 0;
}