编译器是否优化了净零位移?

时间:2018-02-13 21:13:06

标签: c++ c compilation compiler-optimization clang++

我有一些代码,如下面的代码块(我不允许发布原始代码)在.cpp文件中我认为是由clang++编译的Ubuntu clang version 3.5.2-3ubuntu1 (tags/RELEASE_352/final) (based on LLVM 3.5.2)C) 。
它看起来像GoogleTest代码,因为我们使用C来测试我们的size_t const SHIFT = 4; uint8_t var, var2; /* Omitted: Code that sets var to, say 00011000 (base 2) */ var2 = var; var = var << SHIFT >> SHIFT; // [1] result is 00011000 (base 2) (tested with printf) var2 = var2 << SHIFT; var2 = var2 >> SHIFT; // [2] result is 00001000 (base 2) (tested with printf) 代码。反正:

[1]

现在,为什么评论clang成立?我假设相应的行会导致前4位被清零。但我发现这不是真的;该程序只是恢复原始值。

  

这是一些语言定义的行为,还是C++编译出一个假定无用的位移?

(我检查了关联性(使用this table on cppreference.com,假设基本运算符的关联性/优先级在C++版本之间没有差异,可能不在C[1]之间或者,至少不是'当前版本')并且似乎gem 'devise', git: 'https://github.com/plataformatec/devise'处的RHS表达式应该与下面两个语句产生相同的结果)

2 个答案:

答案 0 :(得分:11)

您所看到的是整数促销的结果。当在表达式中使用时,任何类型等级低于int的值都会提升为int

详情见C standard

的第6.3.1.1节
  

2 以下内容可用于intunsigned int的任何地方   使用:

     
      
  • 具有整数类型的对象或表达式(intunsigned int除外)   其整数转换等级小于或等于int和的等级   unsigned int
  •   
  • 类型为_Boolintsigned intunsigned int的位字段。
  •   
     

如果int可以表示原始类型的所有值(由宽度限制,对于a   位字段),该值转换为int;否则,它将转换为unsigned int。这些被称为整数促销。所有其他类型都没有改变   整数促销。

在这种情况下:

var = var << SHIFT >> SHIFT;

var首次升级为int。此类型至少为16位宽,最可能为32位宽。因此,正在操作的值为0x00000018。左移4导致0x00000180,随后右移导致0x00000018

然后将结果存储在uint_8中。由于该值适合此类型的变量,因此不需要转换,并存储0x18

答案 1 :(得分:1)

表达式:

var = var << SHIFT ;
var = var >> SHIFT ; 

在语义上不等于

var = (uint8_t)(var << SHIFT) >> SHIFT ;

这需要:

phoneUtil.parseAndKeepRawInput('202-341-2345', 'ZZ')

说明了两者之间的有效差异 - 观察到的行为不需要优化,而是根据表达式中的类型提升规则通过语言定义必需

也就是说,编译器完全有可能优化轮班。在这种情况下,优化可能不会改变行为定义的结果。