提问人:user16217248 提问时间:11/16/2023 更新时间:11/22/2023 访问量:99
有没有一种故障安全方法可以确定 C 中指针的对齐/尾随位?
Is there a failsafe way to determine the alignment/trailing bits of a pointer in C?
问:
在 C 中,如果一定数量的尾随位为零,则指针与某个指针对齐。这需要提取指针的位,尽管只是有限数量的尾随位。显而易见的方法是强制转换指向位掩码的指针并使用位掩码:uintptr_t
void *my_ptr;
bool aligned_to_16 = (uintptr_t)my_ptr & 15;
但是,C 标准不需要,因为这是一种可选类型。这可能是指针太大而无法放入整数中的情况。但是,这应该无关紧要,因为无论如何我们只关心尾随位。那么,如果我只是投射到 or 呢?uintptr_t
unsigned char
int
好吧,根据这个答案,这仍然是未定义的行为,即使我们不关心会导致值不适合的前导位:
据我所知,指向不同类型指针的指针的所有其他强制转换都是未定义的行为。特别是,如果不强制转换为 char 或足够大的整数类型,则将指针强制转换为其他指针类型可能始终是 UB - 即使没有取消引用它。
我找不到任何符合故障安全标准的方法来提取指针的实际尾部位,例如测试指针对齐方式,不调用任何可选功能或实现定义/未指定/未定义的行为。但是,除了使用格式说明符执行并解析结果之外,实际上还有一种方法吗?snprintf()
%p
答:
不要求指针标识硬件地址。实现可以将每个指针值表示为分配表中的索引和该分配中的偏移量的组合。例如,一些用于 80286 的 C 编译器就是这样工作的。虽然我所知道的执行此类操作的实现通常会以将偏移量的底部位放入整数底部位的方式执行指针到整数的转换,但并不要求它们这样做。
另一方面,该标准没有强制要求所有实现都以 99% 的实现的通用方式运行,这并不意味着编译器编写者通常不应该这样做,而是将偏差限制在那些具有明显或有据可查且令人信服的理由的实现上。它也不意味着程序员应该跳过重重障碍来适应相反的行为,除非他们需要针对这种行为是合理的实现,或者其作者会认为标准对这种偏差的允许本身就是合理的。
评论
显而易见的方法确实是将指针转换为并使用位掩码屏蔽结果值。然而,在您的示例中是未初始化的,因此您确实有一个未定义的行为,编译器可能会利用该行为进行一些不可思议的优化:)此外,如果指针未在 16 个字节上对齐,则这样计算的布尔值将为 true。(uintptr_t)
my_ptr
aligned_to_16
假设目标上存在该类型,并且指针有效,则行为是实现定义的,这与尝试实现非可移植实现相关技巧一样好。uintptr_t
所以答案是:不,没有符合故障安全标准的方法来提取指针的实际尾部位,即使与转换一起使用,但如果你真的需要这些信息,实现定义不是问题。snprintf
%p
需要一个反常的系统(想想 DS9K)来阻止你从这种方法中获得有意义的结果。
摆弄指针的低位通常用于手动优化的实现:
memcpy
、 、 和其他字符串函数memmove
memset
- 对动态类型对象使用标记指针的解释器
- 内存分配器(使用链接指针的低位作为标志)
以上都不是完全可移植的,但适用于大多数当前的架构。在实际需要移植软件之前,您不必担心异国情调的硬件。
最后,你应该问问自己:我真的需要求助于低级的不可移植的黑客,还是我只是沉迷于过早的优化?
评论
SIGBUS
LES BX,DWORD PTR myptr
union u { unsigned short hh[4]; unsigned ll[2]; }; void test(union u *p)
p->hh[0]
p->hh[1]
评论
uintptr_t
ptr->uintptr_t