如何以单字节精度便携地执行指针运算?
请记住:
char
在所有平台上都不是 1 字节sizeof(void) == 1
仅在 GCC 中作为扩展提供- 虽然某些平台可能有指针 deref 指针对齐限制,但算术可能仍需要比最小基本 POD 类型的大小更精细的粒度
如何以单字节精度便携地执行指针运算?
请记住:
char
在所有平台上都不是 1 字节sizeof(void) == 1
仅在 GCC 中作为扩展提供你的假设是有缺陷的 -到处都sizeof(char)
被定义为 1 。
从C99 标准 (TC3)的第 6.5.3.4 节(“sizeof 运算符”)中:
(第 2 段)
sizeof 运算符产生其操作数的大小(以字节为单位),它可以是表达式或带括号的类型名称。
(第 3 段)
当应用于具有 char、unsigned char 或 signed char 类型(或其限定版本)的操作数时,结果为 1。
将这些放在一起时,很明显在 C 中,无论 char 大小是多少,该大小都是一个“字节”(即使在某些给定平台上超过 8 位)。
因此Achar
是最小的可寻址类型。如果您需要以小于 a 的单位寻址char
,您唯一的选择是char
一次读取 a 并使用按位运算符屏蔽char
您想要的部分。
sizeof(char)
保证符合1
C 标准。即使char
使用 9 位或更多位。
所以你可以这样做:
type *pt;
unsigned char *pc = (unsigned char *)pt;
并pc
用于算术。 但是,使用上面的强制转换分配pc
给pt
C 标准是未定义的行为。
如果char
超过 8 位宽,则不能在可移植(ANSI/ISO)C 中进行字节精度指针运算。这里,字节,我的意思是 8 位。这是因为基本类型本身大于 8 位。
根据标准char
是最小的可寻址数据块。您只是无法更精确地解决问题 - 您需要手动进行打包/拆包。
将指针转换为uintptr_t
. 这将是一个指针大小的无符号整数。现在对其进行算术运算,然后将结果转换回您要取消引用的类型的指针。
(请注意,intptr_t
这是已签名的,这通常不是您想要的!uintptr_t
除非您有充分的理由不这样做,否则坚持下去会更安全!)
我不明白你sizeof(void)
在 GCC 中是 1 是想说什么。虽然 typechar
理论上可能包含超过 1 个底层机器字节,但在 C 语言sizeof(char)
中是 1 并且始终恰好是 1。换句话说,从 C 语言的角度来看,char
始终是 1 个“字节”(C 字节,而不是机器字节)。一旦你理解了这一点,你也会明白sizeof(void)
在 GCC 中成为 1 对你没有任何帮助。在 GCC 中,指针上的指针运算与指针上的指针运算的void *
工作方式完全相同char *
,这意味着如果在某些平台char *
上不适用于您,那么void *
也不适用于您。
如果在某些平台上char
的对象由多个机器字节组成,那么访问比完整对象更小的内存单元的唯一方法是使用按位运算来“提取”和“修改”完整对象char
的所需部分。char
C 语言无法直接处理小于char
. 再一次char
总是一个 C 字节。
C99 标准定义了一个字节长的 uint8_t。如果编译器不支持这种类型,你可以使用 typedef 来定义它。当然,您需要不同的定义,具体取决于平台和/或编译器。将所有内容捆绑在一个头文件中并在任何地方使用它。