当 int 和 long 在 C 中具有相同的宽度时,排名有时会失败

Joh*_*ohn 3 c 32bit-64bit

让平台 1 具有int4 个字节的宽度和long8 个字节的宽度。

让平台 2 的宽度为int4 个字节,并且 的宽度与 的宽度long相同int

然后给出:

unsigned int x = 2;
long signed int y = 3;
func(x * y);
Run Code Online (Sandbox Code Playgroud)

在平台 1 上运行时,第一个参数的有效类型funclong signed int。这正如预期的那样。根据第 6.3.1.1.1.4 节,该unsigned int类型与 具有相同的等级signed int。然后,该signed int类型的等级低于long signed int第 6.3.1.1.1.3 节。然后触发乘法结果转换为long signed int类型,遵循第 6.3.1.8.1.4.4 节。伟大的!

在平台 2 上运行时,乘法的结果是long unsigned int为什么?


背景

C99 标准第 6.3.1.1 节第 1 小节第 3 点说:

的等级long long int应大于的等级long int,应大于的等级int,应大于的等级short int,应大于的等级 signed char

这表明的一件事是long int具有比 更高的等级int

此外,C99 标准同段中的第 4 点说:

任何unsigned整数类型的等级应等于相应signed整数类型的等级,如果有的话。

这里的一些事情是unsigned int类型与类型具有相同的等级signed int。同样,该long unsigned int类型与 具有相同的等级long signed int

最后,在第 6.3.1.8 节第 1 小节中,第 4.3 点说:

否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将具有有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。

第 4.4 点:

否则,如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。


测试代码

#include <stdio.h>

#define func(x) _Generic((x), long unsigned int: func_longunsignedint, long signed int: func_longsignedint, signed int: func_signedint, unsigned int: func_unsignedint)(x);

void func_longunsignedint (long unsigned int x)
{
    printf("%s\t%lu\n", __func__, x);
}

void func_longsignedint (long signed int x)
{
    printf("%s\t%ld\n", __func__, x);
}

void func_signedint (signed int x)
{
    printf("%s\t%d\n", __func__, x);
}

void func_unsignedint (unsigned int x)
{
    printf("%s\t%u\n", __func__, x);
}

int main(void)
{
    printf("int width %d\n", sizeof(int));
    printf("long width %d\n", sizeof(long));
    unsigned int x = 2;
    long signed int y = -3;
    func(x * y);
}
Run Code Online (Sandbox Code Playgroud)

对于平台 1,编译时gcc -m64希望将 long 强制为 8 个字节,int 为 4 个字节。

对于平台 2,编译时gcc -m32希望将 long 强制为 4 个字节,int 为 4 个字节。

Kam*_*Cuk 5

我们采用unsignedlong signed int遵循C11 6.3.1.8

  • 否则,如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。

在 64 位平台上,#1 类型long signed int可以表示 的所有值unsigned,因为它有 64 位 vsunsigned有 32 位。所以unsigned转换为long signed int.

在 32 位平台上,#2 类型long signed int不能表示unsigned(UINT_MAX=2^32但是LONG_MAX=2^31-1) 的所有值。所以我们继续...

  • 否则,两个操作数都被转换为与带符号整数类型的操作数的类型对应的无符号整数类型。

...所以在平台 #2 上,“与有符号整数类型对应的无符号整数类型” - 这是long signed int+ unsigned= long unsigned int。所以在平台 #2 上,两个操作数都被转换为long unsigned int,因此你看到的结果。