我的理解是,对常规 ol' short/int/long 类型的某些按位运算要么是依赖于实现的( | & ~ >> ),要么是未定义的( << )
然而,C99 引入了固定宽度的整数类型,并明确地将它们定义为没有填充位的二进制补码精确位。
这是否意味着所有按位运算对于提供它们的平台之间的那些类型来说都是明确定义和可移植的?
例如,这可以在 My Machine™ 上运行,但它保证可以运行吗?
#include <inttypes.h>
#include <stdio.h>
int main() {
uint16_t a = 0xffff;
int16_t b = *(int16_t*)(&a);
printf("%" PRId16 "\n", b);
// Prints '-1'
b <<= 4;
printf("%" PRId16 "\n", b);
// Prints '-16'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用固定宽度类型并不能保证防止与位移相关的未定义行为。C 标准的第 7.20.1.1 节关于精确宽度整数类型指出:
1 typedef 名称
intN_t指定宽度为 N、无填充位和二进制补码表示的有符号整数类型。因此,int8_t表示具有恰好 8 位宽度的这种有符号整数类型。2 typedef 名称
uintN_t指定宽度为 N 且无填充位的无符号整数类型。因此,uint24_t表示具有恰好 24 位宽度的这种无符号整数类型。3这些类型是可选的。但是,如果实现提供宽度为 8、16、32 或 64 位、无填充位且(对于有符号类型)具有二进制补码表示的整数类型,则应定义相应的 typedef 名称。
这里没有提到关于这些类型的位移操作行为的特殊处理。
这里的一个重要方面是整数提升。对于小于 的固定宽度类型,在应用于大多数操作数之前int,它们将首先被提升为int(notint16_t或int32_t)。然后你正在处理潜在的未定义行为。
例如,假设是 32 位int,此代码表现出未定义的行为:
uint24_t x = 0xffffff;
uint24_t y = x << 8;
Run Code Online (Sandbox Code Playgroud)
因为在表达式中x << 8, 的值x被提升为int,然后移位导致一位被移入该值的符号位。