gcc -O3会导致堆栈内存会乱吗?

时间:2023-01-11 02:13:06
在测试i程序的时候发现结果一直都不对,明明前面什么都没改,为什么结果一下就别的不对了。后来发现前天为了跟一个core把 makefile 里的++ 选项加了 -O3,把这个关了程序就对了,有人知道为什么吗? 

7 个解决方案

#1


正常来讲是你程序有bug,比如越界访问,不开优化没让问题显现出来而已。
gcc优化虽然也是有bug,但是被你碰上的概率比你自己程序有bug的概率要小很多。

#2


判断是否越界访问,可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断,可将数组多声明一个元素,并设置数据读写断点在该多出元素对应的地址上。
#include <time.h>
#include <stdlib.h>
#include <windows.h>
int main() {
    int a,b[11];//本来是b[10],为判断哪句越界,故意声明为b[11]

    srand((unsigned int)time(NULL));//按两次F11,等黄色右箭头指向本行时,调试、新建断点、新建数据断点,地址:&b[10],字节计数:4,确定。
    while (1) {//按F5,会停在下面某句,此时a的值为10,b[10]已经被修改为对应0..4之一。
        b[(a=rand()%11)]=0;
        Sleep(100);
        b[(a=rand()%11)]=1;
        Sleep(100);
        b[(a=rand()%11)]=2;
        Sleep(100);
        b[(a=rand()%11)]=3;
        Sleep(100);
        b[(a=rand()%11)]=4;
        Sleep(100);
    }
    return 0;
}


Linux下使用gdb的watch命令设置数据改变断点。

#3


一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

#4


引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

所以说:
gcc -O3会导致堆栈内存会乱吗?理解讨论之前请先学会如何 观察

计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
gcc -O3会导致堆栈内存会乱吗?多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他! gcc -O3会导致堆栈内存会乱吗?

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

#5


引用 4 楼 zhao4zhong1 的回复:
Quote: 引用 3 楼 bravery36 的回复:

一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

所以说:
gcc -O3会导致堆栈内存会乱吗?理解讨论之前请先学会如何 观察

计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
gcc -O3会导致堆栈内存会乱吗?多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他! gcc -O3会导致堆栈内存会乱吗?

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!


连赵老师也跟着起哄



引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。


这种代码的优化根本不影响结果,结果是可以计算出来的。。。

#6


引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

c和c++对于unsigned都规定过overflow行为了,不是UB。优化的不一样那是编译器bug。

#7


gcc -O3会导致堆栈内存会乱吗?

#1


正常来讲是你程序有bug,比如越界访问,不开优化没让问题显现出来而已。
gcc优化虽然也是有bug,但是被你碰上的概率比你自己程序有bug的概率要小很多。

#2


判断是否越界访问,可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断,可将数组多声明一个元素,并设置数据读写断点在该多出元素对应的地址上。
#include <time.h>
#include <stdlib.h>
#include <windows.h>
int main() {
    int a,b[11];//本来是b[10],为判断哪句越界,故意声明为b[11]

    srand((unsigned int)time(NULL));//按两次F11,等黄色右箭头指向本行时,调试、新建断点、新建数据断点,地址:&b[10],字节计数:4,确定。
    while (1) {//按F5,会停在下面某句,此时a的值为10,b[10]已经被修改为对应0..4之一。
        b[(a=rand()%11)]=0;
        Sleep(100);
        b[(a=rand()%11)]=1;
        Sleep(100);
        b[(a=rand()%11)]=2;
        Sleep(100);
        b[(a=rand()%11)]=3;
        Sleep(100);
        b[(a=rand()%11)]=4;
        Sleep(100);
    }
    return 0;
}


Linux下使用gdb的watch命令设置数据改变断点。

#3


一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

#4


引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

所以说:
gcc -O3会导致堆栈内存会乱吗?理解讨论之前请先学会如何 观察

计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
gcc -O3会导致堆栈内存会乱吗?多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他! gcc -O3会导致堆栈内存会乱吗?

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

#5


引用 4 楼 zhao4zhong1 的回复:
Quote: 引用 3 楼 bravery36 的回复:

一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

所以说:
gcc -O3会导致堆栈内存会乱吗?理解讨论之前请先学会如何 观察

计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
gcc -O3会导致堆栈内存会乱吗?多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他! gcc -O3会导致堆栈内存会乱吗?

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!


连赵老师也跟着起哄



引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。


这种代码的优化根本不影响结果,结果是可以计算出来的。。。

#6


引用 3 楼 bravery36 的回复:
一些危险的操作就可能会优化成狗。比如:

unsigned short i = 65535;

++i;
++i;

这种代码一般而言很正常,但是你永远也不知道编译器会如何优化理解你的越界操作。

c和c++对于unsigned都规定过overflow行为了,不是UB。优化的不一样那是编译器bug。

#7


gcc -O3会导致堆栈内存会乱吗?