为了查看结构体中的另一个元素而溢出一个元素是否合法?

Is it legal to overrun one element of a struct to view another?

本文关键字:元素 一个 是否 结构体 另一个 溢出      更新时间:2023-10-16

给定以下人为的示例代码:

struct abc
{
    int x[5];
    int y[5];
};
void main()
{
    struct abc test;
    test.y[0] = 10;
    printf("%n", test.x[5]);
}

程序的输出是10.

虽然不是最好的编程实践,但这确实有效。然而,这是编译器和平台的产物,还是合法的代码?(即由C标准定义?)

即使结果不保证是10,是否有一个实例,这将是"非法的"(即写入内存我不"拥有")?

不,这是不合法的,也不能保证有效。编译器可以在结构体中添加填充,以帮助对齐,具体取决于体系结构等。

编辑:总结这些评论中的一些东西并澄清…

我相信你"拥有"那里的内存,因为正如edA-qa mort-ora-y指出的那样,结构体的memcpy()需要/被期望工作。不过,我不确定这在哪里得到了明确的保证。

话虽这么说,未定义的行为是不惜一切代价避免的。具有未定义行为的程序所做的事情可能在相隔5秒的两次单独运行相同代码之间发生变化。它可能会导致程序中细微的内存损坏、段错误或正常运行,但是没有理由使用依赖于未定义行为的代码。

这是未定义的行为-在这种情况下你(不)幸运。此外(除了提到的填充问题),还有可维护性问题——它非常脆弱——如果有人在两者之间插入其他东西怎么办?我确信这是一个人为的例子,但建议是-不要这样做。

编辑:正如其他人指出的那样,这是不合法的,因为它会导致未定义的行为。我把这句话从我的回答中删掉了。

这有可能导致未定义的行为。你已经在abc结构体中分配了一个10 int长的内存块,所以索引到第5(6)项将带你到y[0],就像你在这个特定的例子中注意到的那样。

当C编译器以您不期望的方式打包结构时,您可能会遇到问题。这称为数据打包或位对齐。当计算机想要从你的数据结构中访问内存时,它会尝试用统一的块来访问整个结构。让我们用一个例子:

struct abc {
    int a;
    char b;
    int c;
};

你期望这个结构体的大小是多少?int是32位,char是8位,所以总大小应该是32 + 8 + 32 = 72位。但是,您会发现在许多系统上,这个结构的大小实际上是96位。原因是char b在末尾被额外的24位打包,以保持变量之间的标准偏移量。

当你在两个不同的地方声明一个结构时,由于编译时的选项或配置,一个结构被打包,而另一个结构没有被打包,这可能会非常令人困惑。

查看位打包和数据对齐或位对齐以获取更多信息。

从技术上讲,这种行为是未定义的。

虽然不是最好的编程实践,但这确实有效。

未定义的行为意味着任何事情都可能发生,包括你所期望的。