首页 文章

类型 - 正确地在不兼容但等效的结构内部指针

提问于
浏览
2

我的目标是这样的:

void alloc(*x)
{
    x->ptr = malloc(100);
}

int main()
{
    struct { int z; int *ptr; } foo;
    struct { int z; double *ptr; } bar;

    alloc(&foo);
    alloc(&bar);
    return 0;
}

函数 alloc 应为不同类型的结构分配内存,这些结构基本相同,但使用不同的指针 .

我尝试解决方案的方式如下:

struct generic {
    int z;
    void *ptr;
};

void alloc(void *x)
{
    struct generic *tmp = x;
    tmp->ptr = malloc(100);
}

要么:

union generic {
    void *p;
    struct {
        int z;
        void *ptr;
    } *g;
};

void alloc(void *x)
{
    union generic tmp = {.p = x};
    tmp.g->ptr = malloc(100);
}

它们是正确的还是它们是否会破坏严格别名,因为实际参数与 generic -struct不兼容且解除引用 xtmp.g 无效?

此外,如果这违反了严格别名,它将如何产生影响?严格别名用于不重新加载特定值,假设它们在没有以正确方式别名(char *,void *,union,兼容类型)时无法被修改 . 使用void-pointer作为参数调用 alloc() ,该参数可能是别名,因此调用者可以更改.1806597_ . 在 alloc() 里面我会专门使用类型惩罚指针 . 那么在这种情况下,如果没有正确重新加载会出现问题?

2 回答

  • 0

    您可以将第二个成员放在结构中(以避免指针兼容性问题) .

    C99 6.2.5.26所有结构类型的指针应具有相同的表示和对齐要求 .

    然后你可以使用union来进行类型惩罚(以避免严格的别名问题) .

    struct generic
    {
        int z;
        union
        {
            struct {int i;} i;
            struct {double d;} d;
        } *ptr;
    };
    
    void alloc(struct generic *x)
    {
        x->ptr = malloc(100);
    }
    
    int main(void)
    {
        struct generic foo;
        struct generic bar;
        alloc(&foo);
        alloc(&bar);
        return 0;
    }
    

    您将不得不访问该结构的成员 . 如果您使用gcc或任何与C11兼容的编译器,则可以使用匿名(未命名)结构成员绕过该问题 .

    似乎没有办法不符合一致的实现 .

  • 1

    这些片段都不是便携式的 .

    至于第一个, tmp 的类型与 x 指向的对象的类型不兼容,即 struct { int z; int *ptr; }struct { int z; double *ptr; } . 因此,取消引用 tmp 违反了严格的别名规则 .

    第二个片段的问题是,指针与不兼容类型的联合只会告诉编译器指针本身是别名,而不是它们指向的对象,因此它仍然会破坏严格的别名(有关严格别名的更多信息,请参阅here) .

    两个片段忽略的是,不同类型的指针实际上可以具有不同的内部表示(尽管很少见),'s why type-punning a double pointer to a void pointer and later on using it as a double pointer again results in the pointer'的位模式被简单地重新解释,但是没有被转换,可能产生陷阱表示并因此产生无效指针(有关更多信息)内部指针表示,请参阅here) .

    总之,两个片段的整体方法都不可移植,需要重新考虑 .

相关问题