所以我有这个代码:
uint32_t s1 = 0xFFFFFFFFU;
uint32_t s2 = 0xFFFFFFFFU;
uint32_t v;
...
v = s1 * s2; /* Only need the low 32 bits of the result */
Run Code Online (Sandbox Code Playgroud)
在以下所有内容中,我假设编译器不能对s1
或s2
仅用于上述示例的初始化器的范围有任何先入之见.
如果我在一个整数大小为32位的编译器上编译它(例如编译x86时),没问题.编译器只是简单地使用s1
和s2
作为uint32_t
类型化的值(不能进一步推广它们),并且乘法将简单地给出结果,如注释所示(模数UINT_MAX + 1
在这种情况下为0x100000000).
但是,如果我在具有64位整数大小的编译器(例如x86-64)上编译它,则可能会从C标准中推断出未定义的行为.整数提升会看到uint32_t
可以提升为int
(64位有符号),然后乘法会尝试乘以2 int
,如果它们恰好具有示例中显示的值,则会导致整数溢出,这是未定义的行为.
我对此是否正确,如果是这样,你会如何以理智的方式避免它?
我发现了这个类似的问题,但涵盖了C++:什么是最好的C++方式来模块化地安全地无符号整数?.在这里,我想得到一个适用于C的答案(最好是兼容C89).我不会考虑让一台糟糕的32位机器可能执行64位乘法,但这是一个可接受的答案(通常在代码中,这会引起关注,32位性能可能更为关键,因为通常那些机器速度较慢).
注意,当使用具有32位int大小的编译器编译时,同样的问题可以应用于16位无符号整数,或者当使用具有16位int大小的编译器编译时,同样的问题可以应用于无符号字符(后者可能与8位CPU的编译器相同) :C标准要求整数至少为16位,因此符合标准的编译器可能会受到影响).
对于C(short,int,long等)中的"标准"有符号整数类型的所有操作,如果它们产生超出[TYPE_MIN,TYPE_MAX]间隔的结果(其中TYPE_MIN,TYPE_MAX是最小值和最大整数值),则表现出未定义的行为可以通过特定整数类型存储的.
但是,根据C99标准,所有intN_t
类型都需要具有二进制补码表示:
7.8.11.1精确宽度整数类型
1. typedef名称intN_t指定有符号整数类型,其宽度为N,无填充位和二进制补码表示.因此,int8_t表示具有正好8位宽度的有符号整数类型.
这是否意味着intN_t
C99 中的类型在整数溢出的情况下表现出良好定义的行为?例如,这段代码定义明确吗?
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
printf("Minimum 32-bit representable number: %" PRId32 "\n", INT32_MAX + 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)