是否将数组转换为C中可移植的同构struct?

Bra*_*iak 16 c struct

考虑以下同构结构:

struct myStruct {
    void* a;
    char* b;
    int* c;
};
Run Code Online (Sandbox Code Playgroud)

我相信它是同类的,因为所有的数据类型都是指针.

鉴于此结构,以下代码在C99中是否有效且可移植?

int main()
{
    void* x = NULL;
    char* y = "hello";
    int* z = malloc(sizeof(int) * 10);
    z[2] = 10;

    void** myArray = malloc(sizeof(void*) * 3);
    myArray[0] = x;
    myArray[1] = y;
    myArray[2] = z;

    struct myStruct* s = (struct myStruct*)myArray;

    printf("%p %s %d\n", s->a, s->b, s->c[2]);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我知道结构通常会在组件之间添加填充以保持结构的大小一致,但是,因为指针的类型都是相同的,是否可以安全地假设不添加填充?我不一定要问是否有100%的保证(我明白这完全是特定于实现的,并且编译器可能因为不明原因而添加填充),更多我要求填充可能添加到同构结构的原因,如有任何理由的话.

Som*_*ude 19

不,它不便携.指针的大小实际上可能不同,这意味着您的结构中可能存在填充.

大多数现代平台上,这不会成为问题,但标准中没有任何内容表明所有指针的大小必须相同.只有那些指针可以隐式转换为和转换void *.

指针大小不同的平台的一个很好的例子是DOS(仍在主动使用,例如在嵌入式系统上)和其他16位分段系统.

  • @BradenSteffaniak这有点难以回答.我想说*可能*但我不想赌它. (3认同)
  • @Some程序员伙计:实际上如果内存服务这在DOS中是完全安全的,至少我使用的Turbo C编译器,以及我用于不同(非功能)指针大小的嵌入式编译器.通常,不同的内存空间用显式限定符标记(在DOS情况下为"near"和"far"),而未标记的限定符到达相同的内存空间.这确实打破了各种各样的假设,例如我现在正在一个系统上编写代码,其中未修饰的指针/`size_t` /`intptr_t`是8位,而大多数都是通过扩展的16位指针到达的. (2认同)
  • 此外,如果编译器认为布局更有效地解决问题,编译器是否完全可以自由地在结构中插入填充字节?可能不太可能有指针,但对于任何其他数据类型,它可能是一个问题. (2认同)

250*_*501 12

代码违反了别名规则.void*和struct myStruct类型不兼容,在这种情况下没有例外.printf语句中的struct指针的取消引用会导致未定义的行为:

printf("%p %s %d\n", s->a, s->b, s->c[2]);
Run Code Online (Sandbox Code Playgroud)

即使结构与三个void指针具有相同的大小,没有填充,并且具有相同的对齐要求,也是如此.