这个变量的值在我的C代码中是如何变化的?

Ben*_*Ben 1 c

我在C中遇到过一个我以前从未遇到的奇怪问题.我已将其缩小到以下非常简单的片段.

变量是全局变量和类型:

    int cpd;
    int nPart;
Run Code Online (Sandbox Code Playgroud)

这里是相关的代码片段,我逐渐将其删除到产生问题所需的最低限度:

    printf("\ncpd1: %d\n",cpd);

    int p;
    for(p=1;p<=nPart;p++)
    {
        printf("\ncpd2: %d\n",cpd); exit(0);
    }
Run Code Online (Sandbox Code Playgroud)

...我得到的输出是这样的:

cpd1: 17

cpd2: 0
Run Code Online (Sandbox Code Playgroud)

这怎么可能?!cpd还没有被重新分配,没有调用任何函数......但它改变了吗?怎么样?!?!

这已经让我慢慢疯了一段时间了......所以任何想法?

谢谢你的时间,本.

编辑:当我从gcc的makefile参数中删除-02时,打印语句告诉我cpd = 0!

编辑:好的,我刚刚发现一个全局声明的变量,初始化为4.0,然后从未修改过的变量现在显然是1.51086e-311 ...某处出了点问题......

编辑:已解决!:我有一个1000大小的数组,需要超过4000,并试图写这个是破坏它周围的记忆.事实是,这些数组不会在那些打印语句附近的任何地方访问,但它可以在相同的函数中访问,但更早(大函数!).打印语句之间的奇怪差异必须是使用-O2的一些奇怪的假象,因为没有-O2,两个打印的cpd打印损坏的版本.谢谢大家,没有你的帮助,我不会这样做!

Han*_*ant 15

由于缓冲区溢出导致的堆栈帧损坏通常是对此的解释.这是一个例子:

#include <stdio.h>
#include <string.h>

int main()
{
  int cpd;
  char msg[4];
  cpd = 17;
  printf("%d\n", cpd);
  strcpy(msg, "Oops");
  printf("%d\n", cpd);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

17
0
Run Code Online (Sandbox Code Playgroud)

"msg"字符串缓冲区太短一个字符,字符串终止符会覆盖"cpd"的值.

找到原因的最佳方法是使用调试器的数据断点功能.在函数入口点上设置常规断点.然后找到"cpd"变量的地址,并在其上设置一个字节大小的数据断点.一旦cpd值改变,调试器就会停止.

请注意,这不一定适用于优化代码,"cpd"值可能存储在寄存器中.这是另一种可能的解释,为什么它在不同的陈述中的价值不同.

  • +1.我同意缓冲区溢出通常是导致这些"魔法"错误的原因. (4认同)
  • 我<3你们所有人!我有一个大小为1000的数组,需要超过4000.事实上,这个数组不能在那些打印语句附近的任何地方访问,但是**在同一个函数中被访问,但是更早.打印语句之间的奇怪差异必须是使用-O2的一些奇怪的假象,因为没有-O2,两个打印的cpd打印损坏的版本.谢谢大家,没有你的帮助,我不会这样做! (2认同)

zeb*_*box 5

我能想到的唯一可能的原因是你声明了另一个本地int cpd变量.作为一个例子,我拿了你的代码并稍微修改它以添加另一个int cpd声明并保持未初始化:
注意我必须设置nPart = 1所以for循环执行至少一次

#include <stdio.h>

int cpd;
int nPart = 1;

int main (int argc, char ** argv)
{
 printf("\ncpd1: %d\n",cpd);
 int cpd;


    int p;

    for(p=1;p<=nPart;p++)
    {
        printf("\ncpd2: %d\n",cpd); 
  break;
 }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我得到以下输出:
cpd1:0

cpd2:2130567168

正如预期的那样,全局变量cpd为0,本地cpd未初始化,几乎可以是任何32位值.

  • +1:我没想过阴影. (2认同)