【发布时间】:2014-11-18 18:42:03
【问题描述】:
所以我有这个代码:
uint32_t s1 = 0xFFFFFFFFU;
uint32_t s2 = 0xFFFFFFFFU;
uint32_t v;
...
v = s1 * s2; /* Only need the low 32 bits of the result */
在以下所有内容中,我假设编译器对s1 或s2 的范围没有任何先入之见,初始化程序仅用于上面的示例。
如果我在具有 32 位整数大小的编译器上编译它(例如在为 x86 编译时),没问题。编译器将简单地使用s1 和s2 作为uint32_t 类型值(无法进一步提升它们),并且乘法将简单地给出注释所述的结果(模UINT_MAX + 1,在这种情况下为0x100000000 )。
但是,如果我在具有 64 位整数大小的编译器上编译它(例如 x86-64),我可以从 C 标准推断出未定义的行为。整数提升将看到 uint32_t 可以提升为 int(64 位有符号),然后乘法将尝试将两个 int 相乘,如果它们恰好具有示例中显示的值,则会导致整数溢出,这是未定义的行为。
我对此是否正确,如果正确,您将如何以理智的方式避免它?
我发现了这个类似的问题,但涵盖了 C++:What's the best C++ way to multiply unsigned integers modularly safely?。在这里,我想得到一个适用于 C 的答案(最好与 C89 兼容)。我不会考虑让可能执行 64 位乘法的糟糕 32 位机器成为可接受的答案(通常在需要关注的代码中,32 位性能可能更关键,因为通常那些机器速度较慢)。
请注意,当使用 32 位 int 大小的编译器编译时,同样的问题可能适用于 16 位无符号整数,或者当使用具有 16 位 int 大小的编译器编译时,同样的问题可能适用于无符号字符(后者可能在编译器中很常见) 8 位 CPU:C 标准要求整数至少为 16 位,因此符合标准的编译器可能会受到影响。
【问题讨论】:
-
int即使在大多数现代 64 位架构上也是 32 位 en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models -
哦,来吧。 anything 是用 C 定义的吗?
-
@harold,是的:
__STDC__是。 -
@Tim:我专门为此发布了它,尽管现在我意识到我实际上可能需要浏览设置为编译器 int 大小的整个项目独立(目前在 32 位和 64 位上都可以正常工作)来检查这些乘法和其他我认为理所当然的东西。证明你永远无法了解潜伏在 C 阴影下的所有野兽......
-
@TimSeguine 如果操作数之一是更宽的 int,则可以接受从 uint 到 int 的提升,但是将两个 uint 转换为 int 是邪恶的。
标签: c undefined-behavior