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

标签 c 32bit-64bit

让平台 1 的宽度为 int 4 个字节和 long 的宽度8 个字节。

让平台 2 的宽度为 int 4 个字节和 long 的宽度与int的宽度相同.

然后给出:

unsigned int x = 2;
long signed int y = 3;
func(x * y);

在平台1上运行时,func的第一个参数的有效类型是long signed int .这符合预期。在 § 6.3.1.1.1.4 之后,unsigned int类型与 signed int 具有相同等级.然后它也遵循signed int type 的排名低于 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 点说:

The rank for long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater that the rank of short int, which shall be greater than the rank of signed char.

这表明 long int排名高于 int .

另外,C99标准同段第4点说:

The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any.

这里有几件事是 unsigned int类型与 signed int 具有相同等级类型。同样,long unsigned int类型与 long signed int 具有相同等级.

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

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

和第 4.4 点:

Otherwise, if the type of the operand with signed integer type can represent all values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.


测试代码

#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);
}

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

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

最佳答案

我们采用unsignedlong signed int 并遵循C11 6.3.1.8 :

  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

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

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

  • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

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

关于c - 当 int 和 long 在 C 中具有相同的宽度时,排名有时会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63881610/

相关文章:

字符指针赋值段错误

c - C中带有变量的“extern”有什么用?

你能解释一下以下 C 代码的输出吗?

c++ - 将宏设置为值,如果为空

c - SIGALRM 中断系统调用

c++ - 检测 32 位或 64 位 Windows

java - 32 位 JVM 提交 >3G 虚拟内存

.net - CPU架构独立的P/Invoke : Can the DllName or path be "dynamic"?

c++ - MS Visual Studio Professional 2013 - C++ 为 32 位和 64 位操作系统编译单个可执行文件?

windows - 32 位进程上线程的最大内存大小