【问题标题】:C bitwise-shift: right operand considered for implicit type-conversion?C按位移位:考虑隐式类型转换的右操作数?
【发布时间】:2017-08-04 20:50:21
【问题描述】:

gcc 4.8.4 警告 1u << 63ul​(假设 64 位 long 和 32 位 int)并计算 0。理所当然(在转移之前没有从1u 升级到1ul)?

ISO/IEC 9899:201x, 6.3.1.8(通常的算术转换):“许多期望算术类型的操作数的运算符会导致转换”; 6.5.7(按位移位运算符):“对每个操作数执行整数提升......”。

但我不能下结论。哪些是“许多操作员”?据我了解,“整数提升”不适用于比int 更宽的类型(我是否正确?),但标准没有明确说明隐式类型不考虑按位移位的右操作数转换。

【问题讨论】:

  • @Olaf:仅仅因为某些事情对你来说是显而易见的并不意味着嘲笑某人提出这个问题是合适的。
  • @DietrichEpp:嗯,从问题中引用的文字中确实不清楚。但 6.5.7 的引文确实提供了答案,正如我(希望)在我的回答中阐明的那样。
  • 此处有关整数提升和常用算术转换的信息:stackoverflow.com/questions/17312545/…

标签: c implicit-conversion bit-shift


【解决方案1】:

每个操作都单独记录。例如,n1548 §6.5.5 “乘法运算符”¶3

对操作数执行通常的算术转换。

第 6.5.7 节“按位移位运算符”中省略了该短语。相反,它说:

对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。 …

由于有关按位移位运算符的部分没有提及“通常的算术转换”,因此不会发生这种转换。

【讨论】:

  • n1548 不是标准的,甚至不是作为参考的最终草案安全。 n1570 确实包含此语句。 OP 甚至引用了这段话。
  • @Olaf:如果您愿意,请随时参考实际标准编辑答案。
  • @DietrichEpp 感谢您提示每个操作都单独记录(没有列出那些“许多操作员”)。然后必须确切地知道“整数提升”是什么意思(特别是比int 更宽的类型保持不变)。我犯了一个错误,专注于它所做的事情,而忘记了它明确不做的事情。
  • 我冒昧地澄清了答案。可以将其解读为好像省略了“整数促销...”这一短语,但事实并非如此。
【解决方案2】:

“通常的算术转换”包括到浮点类型的转换以及如何确定两个操作数的通用类型。

Bitshifts 不适用于浮点类型,仅适用于整数(约束,6.5.7p2)。与其他仅采用整数的二元运算符(例如位与)不同,两个操作数不直接组合以获得结果;操作不需要通用类型。因此,每个操作数都是独立提升的(来自您的引文:“整数提升是在每个操作数上执行”)。

阅读整段 6.5.7p3 就清楚了:

对每个操作数执行整数提升。 结果的类型是提升的左操作数的类型。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

注意强调的句子,它阐明了结果类型仅由左操作数确定。从那和最后一句话得出,正确的操作数的intunsigned int 对于所有当前的实现来说已经绰绰有余了。 int (INT_MAX) 的最低上限是 32767 - 比任何实现的任何标准类型中的位数都多得多,即使我们考虑将来有 1024 位和更多位的更宽整数。

另请注意,您的代码会调用未定义的行为,除非您的平台具有至少 64 位的unsigned int(最后一句)。

编译器会正确警告您的代码调用未定义的行为。 不需要警告,但您应该很高兴它确实如此。认真对待!如果您调用未定义的行为,程序的任何行为都是正确的。

如果您想要 64 位类型,请使用 uint64_t。对于常量,请使用宏 UINt64_C(1),它会生成一个 至少 64 位 (uint_least64_t) 的整数常量。两者均由stdint.h提供。


关于您的其他问题:

从 6.3.1.1p2:

如果 int 可以表示原始类型的所有值(受宽度限制,对于位域),则该值将转换为 int;否则,它将转换为无符号整数。这些被称为整数促销。 整数提升不会改变所有其他类型。

【讨论】:

  • 这个理由不正确,因为通常的算术转换适用于其他按位运算符,例如&
  • @DietrichEpp:确实。但这对我来说似乎是标准的缺陷,而不是故意的。不过,这并没有使我的陈述出错,它们毫无意义的,就像“仅整数”约束一样,整数促销无论如何都适用。
  • 不,这不是标准中的缺陷。这是你可以写的方式,例如,x | 1,即使xint 宽。
  • @DietrichEpp:我更改了大部分文本。希望现在是正确的。
  • @Loic:很高兴我能帮上忙。如果它回答了您的问题,请考虑接受它。这是说“谢谢”的堆栈溢出方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
  • 1970-01-01
相关资源
最近更新 更多