问题描述
让平台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
具有相同的等级。然后,根据第6.3.1.1.1.3节,signed int
类型的等级比long signed int
低。然后,按照第6.3.1.8.1.4.4节的要求,将乘法结果转换为long signed int
类型。太好了!
在平台2上运行时,相乘的结果为long unsigned int
。 为什么?
背景
C99标准第6.3.1.1节第1小节第3点说:
long long int
的等级应大于long int
的等级, 大于int
的等级,大于short int
的等级signed char
的等级,该等级应大于long int
。
这表明,int
的排名高于unsigned
。
此外,C99标准同一段落中的第4点表示:
任何
signed
整数类型的等级应等于 相应的unsigned int
整数类型(如果有)。
从这里开始,有两件事是signed int
类型与long unsigned int
类型具有相同的等级。同样,long signed int
类型与#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",x);
}
void func_signedint (signed int x)
{
printf("%s\t%d\n",x);
}
void func_unsignedint (unsigned int x)
{
printf("%s\t%u\n",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);
}
具有相同的排名。
最后,在第6.3.1.8节第1小节的第4.3点中说:
否则,如果具有无符号整数类型的操作数具有等级 大于或等于另一个操作数类型的等级,则 带符号整数类型的操作数将转换为 无符号整数类型的操作数。
并指出4.4:
否则,如果带符号整数类型的操作数的类型可以 用无符号整数表示操作数类型的所有值 类型,然后将无符号整数类型的操作数转换为 带符号整数类型的操作数的类型。
测试代码
gcc -m64
对于平台1,希望使用gcc -m32
进行编译,以强制将long强制为8个字节,并将int为4个字节。
对于平台2,希望使用bulk_update()
进行编译,以强制将long强制为4个字节,并将int为4个字节。
解决方法
我们采用unsigned
和long signed int
并遵循C11 6.3.1.8:
- 否则,如果带符号整数类型的操作数的类型可以表示带无符号操作数类型的所有值 整数类型,然后将转换为无符号整数类型的操作数 到带符号整数类型的操作数的类型。
在64位平台#1上,类型long signed int
可以表示unsigned
的所有值,因为它具有64位,而unsigned
具有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
,因此您看到的结果。