我有一些代码,如下面的代码块(我不允许发布原始代码)在.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表达式应该与下面两个语句产生相同的结果)
答案 0 :(得分:11)
您所看到的是整数促销的结果。当在表达式中使用时,任何类型等级低于int
的值都会提升为int
。
详情见C standard
的第6.3.1.1节2 以下内容可用于
int
或unsigned int
的任何地方 使用:
- 具有整数类型的对象或表达式(
int
或unsigned int
除外) 其整数转换等级小于或等于int
和的等级unsigned int
。- 类型为
_Bool
,int
,signed int
或unsigned 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')
说明了两者之间的有效差异 - 观察到的行为不需要优化,而是根据表达式中的类型提升规则通过语言定义必需。
也就是说,编译器完全有可能优化轮班。在这种情况下,优化可能不会改变行为定义的结果。