【问题标题】:Does multiplying unsigned short cause undefined behaviour?乘以 unsigned short 会导致未定义的行为吗?
【发布时间】:2016-02-17 09:08:22
【问题描述】:

作为“https://stackoverflow.com/questions/33732041/why-static-castunsigned-intushrt-maxushrt-max-yields-correct-value”的后续行动

我在问自己,在某些情况下,是否将排名低于int 的所有类型(除了一些例外)提升到int 以执行算术运算可能会导致 UB。

例如:

unsigned short a = 0xFFFF;
unsigned short b = a*a;

由于 unsigned short 被提升为 int 以进行算术运算,这将导致:

unsigned short a = 0xFFFF;
unsigned short b = (int)a*(int)a;

由于(int)0xFFFF*(int)0xFFFF 导致溢出,而​​有符号类型的溢出是UB:x*y > INT_MAX 的情况下,两个无符号短裤x,y 相乘会导致未定义的行为


更新

这个问题专门针对int是32位,short是16位的情况。

【问题讨论】:

  • 是的。结果是不使用转换等级低于int 的无符号类型进行算术运算。一个更简单的规则是不要对数字使用无符号类型,而是将它们用于位摆弄。
  • 是的,这是有符号整数溢出导致 UB。一个令人讨厌的历史缺陷,它可以伪装起来,因为uint16_t 通常被实现为unsigned short 的typedef。从理论上讲,uint32_t 甚至会出现同样的问题,因为没有什么能阻止编译器使 short 在具有 64 位 int 的系统上成为 32 位。
  • @M.M:其实short 并没有什么特别之处。在算术运算发生之前,任何小于int 的无符号类型都将被提升为int。如果 int 是 64 位,则尤其适用于 uint32_t
  • 我认为你可以(理论上)通过乘以size_ts 来产生相同的 UB,因为我没有在标准中找到它必须至少与 int 一样大的约束。 twitter.com/fugueish/status/637715389519015941

标签: c++ c++11 types casting integer-promotion


【解决方案1】:
C++11 §3.9.1/4,完整引用:

声明为unsigned 的无符号整数应遵守算术模2 定律n 其中n 是数字 该特定整数大小的值表示中的位数。

除了关于“声明unsigned”的稍微误导性的措辞之外,这似乎适用于每个仅涉及某些给定无符号类型的参数的算术表达式,将产生模2的结果n em> 表示该类型。

但是,对于转换等级低于int 的无符号类型,根本没有算术表达式:明显的此类表达式中的所有参数都至少转换为(1)int , 或取决于 C++ 实现的数字范围,最高可达 unsigned int

因此,a*b 其中abunsigned short 值,(2)可以具有正式的未定义行为。因为它不是unsigned short 表达式。它(实际上)是一个int 表达式。

也就是说,使用一个合理的编译器,它不会在注意到正式 UB 的地方引入特殊的大小写,并且在实践中使用 8 位字节和int 可以表示的 unsigned short 最大值,以及带有符号的常见二进制补码整数表示,当转换回unsigned short 时,结果将是好像它是unsigned short 范围内的模运算。这是因为二进制补码在机器代码级别只是范围以 0 为中心的模运算。


(1) 在实践中,通常会使用每字节 8 位的实现,其中 unsigned short 的最大值非常适合 int 范围,所以在练习我们谈论的是转换到int
(2) 例如,对于 16 位 unsigned short 和 32 位 int,(216 -1)2 = 232-2×216+1 > 231- 1,其中最后一个值是最大正 int 值。

【讨论】:

  • 知道为什么不将无符号类型提升为unsigned int吗?这样就可以解决问题了。
  • @SimonKraemer:我不知道。但我记得 James Kanze 曾经说过,转换规则很早就改变了。这与在表达式中混合有符号和无符号的问题有关。
  • 好吧,在现实生活中应该没关系。感谢您挖掘规则。
  • @CodesInChaos:至少有一个与您的断言兼容的示例会很好。这是一个例子,其中 gcc 编译器,对于给定的代码,是合理的:coliru.stacked-crooked.com/a/036e12a08cedfd95
  • @Alf 典型示例是针对有符号整数将x + 1 > x 优化为true。由-fstrict-overflow 控制,它是 GCC 的-O2 的一部分。另请参阅 LLVM 博客上的 What Every C Programmer Should Know About Undefined Behavior #2/3
【解决方案2】:

当您将unsigned short * unsigned short 相乘时,就会有一个implicit conversion,并且该值在C++11 中被转换为intdocumentation 说:

小整数类型(如 char)的 prvalues 可以转换为 较大整数类型(例如 int)的纯右值。特别是, 算术运算符不接受小于 int 的类型作为参数

所以它会导致一个未定义的行为。

【讨论】:

    猜你喜欢
    • 2014-08-11
    • 2016-09-04
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 2017-04-08
    • 2013-10-02
    相关资源
    最近更新 更多