为了查看结构体中的另一个元素而溢出一个元素是否合法?
Is it legal to overrun one element of a struct to view another?
给定以下人为的示例代码:
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位打包,以保持变量之间的标准偏移量。
当你在两个不同的地方声明一个结构时,由于编译时的选项或配置,一个结构被打包,而另一个结构没有被打包,这可能会非常令人困惑。
查看位打包和数据对齐或位对齐以获取更多信息。
从技术上讲,这种行为是未定义的。
虽然不是最好的编程实践,但这确实有效。
未定义的行为意味着任何事情都可能发生,包括你所期望的。
- lower_bound()返回最后一个元素
- 使用std::transform将一个范围的元素添加到另一个范围中
- 我想访问std::unique_ptr中的一个特定元素
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 删除映射和分割错误中的一个过去结束元素
- Lower_bound不适用于具有 3 个元素的向量的最后一个元素
- 查找数组中第一个最小值和最后一个最大值元素之间的算术平均值
- 检查 2D 网格的某个元素是否与另一个元素共享对角线、水平线或垂直线
- 如何创建一个所有行大小不同的 2D 数组,并且用户将指定每行将有多少个元素?
- 仅显示链表的最后一个元素
- 为什么在 std::map 上移动无法将元素从一个映射移动到另一个映射
- 查找最小的下一个更大的元素
- push_back通过自行创建的对象获取最后一个元素的向量
- 使用 map.end() 访问 map 的最后一个元素
- 如何知道地图中的最后一个元素是否被删除?
- 选择一个元素而不是一个对象的数组的原因
- std::矢量保存 只推送最后一个元素
- 为什么这个选择排序算法仍然切换一个元素,当它已经是其他元素中最小的元素时?
- 动态分配列表 - 创建一个函数,用于删除所有包含偶数值的元素