在C语言中,整数运算的中间结果使用哪种精度?

在C语言中,整数运算的中间结果使用哪种精度?,c,typedef,C,Typedef,假设我有以下变量和以下等式: int16_t a,b,c,d; int32_t result; result = a*b - c*d; ab和cd的中间结果将存储在16位还是32位 PS:我可以比写问题更快地测试这个问题,我想知道C规范说了什么。中间结果将是int类型 任何小于int的类型都将首先升级。这些整数提升是针对类型int或unsigned**。因此,数学运算必须发生在int、unsigned或原始类型 int16\t当然更窄,或者与int相同 结果的类型与中间结果的类型无关 int

假设我有以下变量和以下等式:

int16_t a,b,c,d;
int32_t result;

result = a*b - c*d;
ab和cd的中间结果将存储在16位还是32位


PS:我可以比写问题更快地测试这个问题,我想知道C规范说了什么。

中间结果将是
int
类型

任何小于
int
的类型都将首先升级。这些整数提升是针对类型
int
unsigned
**。因此,数学运算必须发生在
int
unsigned
或原始类型

int16\t
当然更窄,或者与
int
相同

结果的类型
与中间结果的类型无关

int16_t a,b,c,d;
int32_t result = a*b - c*d;
要使所有平台都具有可移植性,包括
int
窄于
int32\t
的平台,请确保使用至少32位数学计算产品

#include <stdint.h>
int32_t result = INT32_C(1)*a*b - INT32_C(1)*c*d;
#包括
int32_t result=int32_C(1)*a*b-int32_C(1)*C*d;

当然,结果存储为32位,可能是扩展中间结果的符号

对于具有32位或64位
int
的机器,中间结果将适合
int32\u t
,值没有任何变化,没有例外。结果为
-2147450880至2147450880
(80008000至7FFF8000)

**永远不要长,即使在平台上也不要长。

我很快就会更新这个答案。我不再相信该标准允许将
int16\t
提升为
long
。但是,在一些非常模糊的情况下,它可以升级为
unsigned int
。整数转换秩规则对于外来系统有一些奇怪的结果。

这几乎是正确的。有两种模糊且不太可能的情况,中间结果的类型为
long int

int16\u t
必须是不带填充位的16位2的补码整数类型。
int16\u t
类型的操作数将升级为可以表示
int16\u t
类型的所有可能值的类型,并且其宽度至少与
int
相同

标准要求
int
的范围至少为-32767到+32767

假设
int
使用1的补码或符号和幅度表示,或者使用2的补码表示,但通常为
-32768
的表示被视为陷阱表示。然后,
int
不能保存类型为
int16\u t
的所有值,必须将操作数提升为
long
(这保证具有足够宽的范围)

要实现这一点,该实现必须同时支持具有受限16位范围的
int
类型(很可能不是2的补码)和适合
int16\t
的类型,这意味着它具有2的补码表示,并且没有填充位或陷阱表示。例如,1的补码系统更可能没有这种类型,因此它根本不会定义
int16\t
(尽管它会定义
int\u fast16\t
int\u least16\t

对于几乎所有的实际实现,
int
可以保存
int16\u t
类型的所有值,因此中间结果是
int
类型的。对于几乎所有剩余的真实世界或假设系统,
int16\t
。对于假设的一小部分不存在但符合条件的C实现,中间结果的类型为
long int

更新:chux指出了我论点中可能存在的弱点。在一篇评论中,他认为6.2.6.2第2段说,整数类型可以使用两个补码、一个补码或符号和大小来表示,其目的是要求所有整数类型使用相同的表示(当然,位数不同,但都使用相同的选项)

J.3.5中非规范性文本的措辞,表示:

是否使用符号和大小表示有符号整数类型, 二补,还是一补,是否超常 值是陷阱表示或普通值

是实现定义的,在解释中倾向于支持这一点。如果不同的整数类型在这方面可能有所不同,那么对于每个整数类型都应该这样说

然而:

  • 6.2.6.2p2并没有明确地说所有整数类型都必须使用相同的表示形式,我也不知道还有其他任何东西暗示它们必须这样做

  • 支持具有不同表示形式的整数类型可能很有用。例如,硬件可能支持1的补码,但为了实现依赖于
    int16\t
    等的代码,实现可能在软件中支持2的补码整数,或者硬件可能直接支持这两种表示。(我猜想作者没有考虑这种可能性,但我们只能按照标准实际所说的去做。)
  • 在任何情况下,实际上没有必要调用非二元补码表示来构造一个案例,其中
    int16\u t
    提升为
    long int

  • 假设如下:

    • 所有整数类型都使用2的补码表示
    • INT_MAX==+32767
    • INT\u MIN==-32767
    • 带有符号位1和所有值位0的
      int
      是陷阱表示
    int
    没有填充位,但通常表示
    -32768
    的位模式是陷阱表示。N1570 6.2.6.2第2段明确允许这样做

    但是
    int16\t