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

时间:2016-03-25 01:48:43

标签: c typedef

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

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

result = a*b - c*d;

b和c d的中间结果将以16位还是32位存储?

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

2 个答案:

答案 0 :(得分:4)

中间结果的类型为int

首先会提升比int更窄的任何类型。这些整数促销适用于intunsigned **类型。因此,数学必须出现在intunsigned或原始类型。

int16_t肯定比int更窄或相同。

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

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;

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

对于具有32位或64位int的计算机,中间结果将适合int32_t,而值没有任何变化,没有异常。结果为-2147450880 to 2147450880(80008000至7FFF8000)。

**从不long,甚至不在unicorn平台上。

答案 1 :(得分:3)

我很快就会更新此答案。我不再相信该标准允许将int16_t提升为long。但在一些极其模糊的案例中,它可以推广到unsigned int。对于奇异系统,整数转换排名规则有一些奇怪的结果。

chux's answer 几乎正确无误。有一些模糊且不太可能的情况,其中间结果是long int类型。

int16_t必须是16位二进制补码整数类型,没有填充位。类型为int16_t的操作数将被提升为一种类型,该类型可以表示int16_t类型的所有可能值,并且至少与int一样宽。

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

假设int使用1的补码或符号和幅度表示,它使用2的补码表示,但通常为-32768的表示形式将被处理作为陷阱表示。然后int 无法保存int16_t类型的所有值,并且必须将操作数提升为long(保证范围足够宽)。< / p>

要实现这一点,实现必须支持两个 int类型,具有受限制的16位范围(很可能不是2的补码)一种适合int16_t的类型,意味着它具有2的补码表示,没有填充位或陷阱表示。例如,1的补码系统更可能没有这样的类型,因此它根本不会定义int16_t(尽管它会定义int_fast16_tint_least16_t

对于几乎所有实际实现,int都可以包含int16_t类型的所有值,因此中间结果的类型为int。对于几乎所有剩余的现实世界或假设系统,将不提供int16_t。对于假设的一小部分不存在但符合C的实现,中间结果的类型为long int

更新: chux指出我的论点中可能存在的弱点。在评论中,他认为N1570 6.2.6.2第2段说明整数类型可以使用二进制补码表示,一个补码,或符号和大小,旨在要求所有整数类型使用相同的表示(当然,位数不同,但都使用相同的那些选择)。

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

  

是否使用符号和幅度表示有符号整数类型,   两个补码,或者说是“补码”,是否非同寻常   value是陷阱表示或普通值

是实现定义的,倾向于支持解释。如果不同的整数类型在这方面可能不同,则应该为每个整数类型

然而:

  1. 6.2.6.2p2 显式表示所有整数类型必须使用相同的表示形式,并且我不知道其他任何意味着它们必须这样做。< / p>

  2. 支持具有不同表示形式的整数类型可能很有用。例如,硬件可能支持补码,但为了依赖于int16_t等的代码,实现可能在软件中支持两个补码整数。或者硬件可能直接支持两种表示。 (我的猜测是作者没有考虑这种可能性,但我们只能遵循标准实际所说的内容。)

  3. 在任何情况下,实际上都不需要调用非二进制补码表示来构建int16_t提升为long int的情况。

  4. 假设如下:

    • 所有整数类型都使用二进制补码表示。
    • INT_MAX == +32767
    • INT_MIN == -32767
    • 符号位为1的int,所有值位0都是陷阱表示。

    int没有填充位,但通常表示-32768的位模式是陷阱表示。 N1570 6.2.6.2第2段明确允许这样做。

    int16_t 的范围必须为-32768+32767。 7.20.2.1表示INTN_MIN必须完全 - (2 N-1 )(在这种情况下为N==16)。

    因此,在此几乎完全难以置信的但符合规定的实施中,int16_t已定义,但int无法代表int16_t的所有值,因此{{1} }值被提升为int16_t(必须至少为32位)。