使用结构:
struct stree {
union {
void *ob;
struct stree *strees[256];
};
};
C标准(尤其是C11)是否保证ob
是stree[0]
的别名?
答案 0 :(得分:1)
也许。 C标准仅保证以下6.3.2.3:
指向
void
的指针可以与任何对象类型的指针进行转换。指向的指针 任何对象类型都可以转换为指向void
的指针并再次返回;结果应 比较等于原始指针。
从理论上/形式上讲,void*
不需要具有与对象指针相同的内存表示形式。从理论上讲,只要遇到这种转换,它就可以做一些技巧,例如跟踪原始值,以便以后恢复。
实际上,void*
和对象指针在任何理智的系统上具有相同的大小和格式,因为到目前为止,这是满足上述要求的最简单方法。存在具有扩展的对象寻址模式的系统,但是它们不能按C标准使用。相反,他们通过发明near
和far
指针限定符来使用非标准扩展,然后可以将其应用于void*
或对象指针。 (其中的一些示例是低端微控制器和旧的MS DOS。)
最重要的是:为将其移植到疯狂或虚构的系统而进行的设计会浪费大量时间。扔一个static_assert(sizeof(void*) == sizeof(int*), "...")
就足够了。因为在实践中,您不会找到具有神奇或神秘void*
格式的系统。如果您这样做了,那就对付它。
您要记住的是,void*
本身是一种不同的类型,因此通常无法通过另一种指针类型访问void*
存储的内存(严格指针别名)。但是严格的别名规则也有一些例外,通过联合的类型修剪是其中之一。
因此,对于您的union
,可以保证void*
和第一个对象指针是从同一地址开始分配的,但是从理论上讲,它们各自的大小和内部格式也可能不同。实际上,您可以假设它们是相同的,并且因为使用union
并没有破坏严格的别名。
关于最佳做法,首先要避免使用void*
,因为实际上很少有地方需要它们。对于少数需要传递通用指针的情况,通常最好使用uintptr_t
并将结果存储为整数。