Linux下哪些C类型可保证页边界分配后内存拷贝值一致?
问题解答
核心结论
在Linux环境下,只要满足以下两个条件的C类型,都能保证将变量val通过memcpy拷贝到mmap分配的页边界内存后,*(TYPE*)mem与原val值完全一致:
- 类型的对齐要求不超过页边界的对齐级别(Linux下页大小通常为4KB或更大,远高于C标准中所有基础类型的对齐要求);
- 类型没有陷阱表示(trap representation),或者原变量
val的取值不是该类型的陷阱表示。
满足要求的类型清单
- 无符号整数类型:
unsigned char、unsigned short、unsigned int、unsigned long、unsigned long long等。无符号整数的所有位模式都是有效值,不存在陷阱表示。 - 有符号整数类型:
signed char、short、int、long、long long等。Linux系统普遍采用二进制补码表示有符号整数,且无符号位/大小的padding,此时所有位模式都是有效值,无陷阱表示。 - 布尔类型:
_Bool,仅包含0和1两个有效值,无陷阱表示。 - 枚举类型:枚举的底层实现是整数类型(通常是
int),只要底层整数类型满足条件,枚举类型就满足要求。 - 指针类型:
void*、int*等所有指针类型。Linux下指针的对齐要求(如64位系统为8字节,32位为4字节)远小于页对齐级别;且同一进程内,有效的指针值经memcpy字节拷贝后,地址有效性不变,取值与原指针一致。 - 复合类型:成员满足上述条件的结构体、联合体、数组。
memcpy会完整拷贝包括填充字节在内的所有内容,因此拷贝后的复合类型对象与原对象完全一致。
标准依据
- C11标准(ISO/IEC 9899:2011):
- 6.2.6.1p3:无符号整数类型的每一种位组合都是该类型的有效值,不存在陷阱表示。
- 6.2.6.2p2:对于采用二进制补码表示的有符号整数类型,若没有符号和大小信息的padding,则所有位模式都是有效值(Linux系统符合此实现定义)。
- 7.24.2.1p2:
memcpy函数将源对象的字节逐字节复制到目标对象,只要两个对象大小相同,目标对象的内容将与源对象完全一致。 - 6.2.8p1:任何类型对象的对齐要求由实现定义,但基础类型的对齐要求不会超过其自身大小,而Linux的页大小(4KB)远大于所有基础类型的大小,因此页边界分配的内存满足所有基础类型的对齐要求。
补充说明
char类型(包括signed char和unsigned char)之所以能保证一致性,本质是因为其大小为1,对齐要求最低,且无陷阱表示,完全符合上述条件。- 对于Linux下常用的IEEE 754浮点类型,所有位模式要么是有效值,要么是NaN等合法特殊值,不属于陷阱表示,因此只要原变量取值合法,拷贝后也能保证一致性。
内容的提问来源于stack exchange,提问作者Mark Galeck
相关产品推荐
相关产品推荐

