超出结构的一个元素来查看另一个元素是否合法?

Dav*_*fer 8 c c++ standards

鉴于以下设计的示例代码:

struct abc
{
    int x[5];
    int y[5];
};

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

该计划的输出是10.

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

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

Dan*_*ego 12

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

编辑:总结这些评论中的一些内容并澄清......

我确实相信你"拥有"那里的记忆,因为正如edA-qa mort-ora-y指出的那样,结构的memcpy()需要/有望起作用.虽然这是特别保证的,但我不确定.

话虽如此,未定义的行为是不惜一切代价避免的.具有未定义行为的程序可以在相隔五秒钟的相同代码的两次单独运行之间进行更改.它可能会导致程序中的细微内存损坏,段错误或运行正常,但没有理由使用依赖于未定义行为的代码.

  • @Pubby:你对"合法"的定义是什么(*"不会让你入狱"*?) (6认同)
  • 我不再认为在C++ 11中这是未定义的行为.这是一种标准布局类型,这意味着定义了通过memcpy进行复制,因此必须保证填充空间中的内存.虽然我完全同意价值未定义,并且无法保证可以转入下一个成员.但由于标准布局要求,访问位于那里的存储器必须是安全的. (3认同)

Nim*_*Nim 5

这是未定义的行为 - 在这种情况下你是(非)幸运的.更进一步(除了上面提到的填充问题),存在可维护性问题 - 它非常脆弱 - 如果有人在其他方面粘贴其他内容会怎么样.我敢肯定这是一个人为的例子,但建议是 - 不要这样做.


Bre*_*ain 4

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

这有可能导致未定义的行为。您已在 struct abc 中分配了 10 个 int 长的内存块,因此索引到第 5(第 6)项将带您到 y[0],正如您在该特定情况中所指出的那样。

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

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

您预计该结构的大小是多少?int 为 32 位,char 为 8 位,因此总大小应为 32 + 8 + 32 = 72 位。然而,你会发现在很多系统上,这个结构体的大小实际上是96位。原因是 char b 在末尾进行了位打包,并附加了 24 位,以维持变量之间的标准偏移量。

当您在两个不同的位置声明一个结构时,这可能会非常令人困惑,并且由于编译时选项或配置的原因,一个位置会被位打包,而另一个则不会。

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

  • @DavidPfeffer:我不确定接受唯一没有提及“未定义行为”的答案是否正确。当然,这个答案似乎可以安慰你的信念,但实际上你不应该这样做。 (3认同)
  • 它“不”合法,因为它给出了未定义的行为。 (3认同)
  • C++11 标准几乎没有使用“合法”这个词,也没有定义它。在它确实使用它的每种情况下(我可以找到),它描述为“非法”的事物都会被编译器拒绝,或者它描述为“合法”的事物被接受并具有定义的行为。因此,您可以选择您认为它应该意味着什么,但可以优先使用标准术语(“格式良好”、“格式错误”、“UB”) (2认同)