que*_*en3 0 c++ optimization gcc g++
这是测试代码:
#include <stdio.h>
struct test
{
int m[1];
};
struct test2: public test
{
int m1[22];
void set(int x, int y) { m[x] = y; }
};
int main()
{
test2 t;
t.m[1] = 123;
t.set(0, 0);
t.set(1, 1);
printf("%d %d\n", t.m[0], t.m[1]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我没有编译一次,优化编译一次:
$ g++ -O0 testf.cpp
$ ./a.out
0 1
$ g++ -O2 testf.cpp
$ ./a.out
1 123
Run Code Online (Sandbox Code Playgroud)
在我看来,gcc看到数组大小m [1]并优化对它的访问,始终是第一个元素m [0].问题是:它是优化错误还是,某些C++规则被打破,以便gcc可以做它做的事情,如果是,那么什么规则?
请注意,由于额外的m1 [22]内存(在真实应用程序中设计),不会发生内存/堆栈溢出.我不问这是不是一个好的编程风格,我只是好奇得到上面问题的正确答案.
更新:我接受了std详细信息的答案,但最大的帮助是带有以下链接的注释:"struct hack"在技术上是不确定的行为吗?
And*_*owl 12
您的程序有未定义的行为.这里:
t.m[1] = 123;
Run Code Online (Sandbox Code Playgroud)
您正在写入一个越界位置(m是一个元素的数组,并且您正在索引一个不存在的第二个元素),对于以下情况也是如此:
t.set(1, 1);
Run Code Online (Sandbox Code Playgroud)
因为它基本上最终做了:
m[1] = 1;
Run Code Online (Sandbox Code Playgroud)
对于具有未定义行为的程序,您不能指望任何事情 - 尤其是不一致的行为.
Ben*_*igt 10
这是5.7的相关规则:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型...如果指针操作数和结果都指向同一个数组对象的元素,或者指向一个数组对象的元素数组对象的元素,评估不得产生溢出; 否则,行为未定义.
回想一下,t.m[i]它等同于*(t.m+i)指针添加规则.
显然,指针操作数t.m和结果(t.m + 1)不指向同一数组对象的成员.但是,在这种情况下,结果是"一个超过数组对象的最后一个元素".因此指针有效,但不能在严格的指针安全规则下解除引用.由于您试图取消引用它,因此您将回到未定义的行为.
请注意t.m + 1 == t.m1,由于允许编译器在基础子对象和成员之间插入填充,因此无法保证.
另请注意,编译器需要生成对表达式的正确位置的内存访问reinterpret_cast<int*>(reinterpret_cast<intptr_t>(t.m) + i * sizeof (int)),除非它定义__STDCPP_STRICT_POINTER_SAFETY__.但是没有具体说明它将如何与m1数组重叠.而且你可能会覆盖编译器在那里写的某种神奇的元数据(当然更可能是多态类型).
| 归档时间: |
|
| 查看次数: |
382 次 |
| 最近记录: |