指针和指针数组的并集是否可以确保单个指针与数组的第一个元素具有相同的地址?

时间:2019-06-20 10:44:15

标签: c pointers struct union

使用结构:

struct stree {
    union {
        void *ob;
        struct stree *strees[256];
    };
};

C标准(尤其是C11)是否保证obstree[0]的别名?

1 个答案:

答案 0 :(得分:1)

也许。 C标准仅保证以下6.3.2.3:

  

指向void的指针可以与任何对象类型的指针进行转换。指向的指针   任何对象类型都可以转换为指向void的指针并再次返回;结果应   比较等于原始指针。

从理论上/形式上讲,void*不需要具有与对象指针相同的内存表示形式。从理论上讲,只要遇到这种转换,它就可以做一些技巧,例如跟踪原始值,以便以后恢复。

实际上,void*和对象指针在任何理智的系统上具有相同的大小和格式,因为到目前为止,这是满足上述要求的最简单方法。存在具有扩展的对象寻址模式的系统,但是它们不能按C标准使用。相反,他们通过发明nearfar指针限定符来使用非标准扩展,然后可以将其应用于void*或对象指针。 (其中的一些示例是低端微控制器和旧的MS DOS。)

最重要的是:为将其移植到疯狂或虚构的系统而进行的设计会浪费大量时间。扔一个static_assert(sizeof(void*) == sizeof(int*), "...")就足够了。因为在实践中,您不会找到具有神奇或神秘void*格式的系统。如果您这样做了,那就对付它。

您要记住的是,void*本身是一种不同的类型,因此通常无法通过另一种指针类型访问void*存储的内存(严格指针别名)。但是严格的别名规则也有一些例外,通过联合的类型修剪是其中之一。

因此,对于您的union,可以保证void*和第一个对象指针是从同一地址开始分配的,但是从理论上讲,它们各自的大小和内部格式也可能不同。实际上,您可以假设它们是相同的,并且因为使用union并没有破坏严格的别名。

关于最佳做法,首先要避免使用void*,因为实际上很少有地方需要它们。对于少数需要传递通用指针的情况,通常最好使用uintptr_t并将结果存储为整数。