【问题标题】:Why is my variable not being updated?为什么我的变量没有更新?
【发布时间】:2014-05-20 19:26:38
【问题描述】:

我已经定义了一个具有初始值的变量。
单步执行代码时:

  • 我可以看到初始值
  • 我的函数改变了值
  • 当我稍后使用该变量时,它的值错误

发生了什么?

注意:这旨在作为常见问题的参考问题。如果此处的通用答案对您没有帮助,请发布一个包含您完整的实际代码的问题。

【问题讨论】:

  • 我知道你在做什么,但是你可能想在问题中添加一些参考代码以获得更好的质量。
  • 我同意。虽然我已经多次遇到过这个问题,但很难即时想出好的例子。我计划随着时间的推移不断更新这个问题,因为我在这里遇到比我捏造的更好的例子。如果有人能提供更好的例子,我会编辑帖子以反映它们。
  • 只需使用您答案中的示例,甚至是通用的hello world。这是一个为网站定下基调的问题。我们不想邀请所有人在不提供至少一些代码的情况下开始询问代码故障排除问题;)
  • 在编辑之前我会考虑一下。问题是这可能发生的原因有很多,很难想出一个有意义的代码 sn-p 来涵盖多种情况。这就是我描述症状的原因。我在创建这个之前检查了stackoverflow,并且有几个关于这个具体案例的问题,但我希望这个问题成为一个通用的,让人们在发布他们自己的问题之前尝试的所有事情。
  • 如果您想发布这样的示例“错误”帖子,最好的形式是针对您认为的“典型”原因提供一些答案。没有上下文的错误问题有些空洞——尤其是在人们可能使用十几种不同的 c 编译器之一的环境中!

标签: c debugging embedded


【解决方案1】:

变量可能不保留值的原因有多种。虽然有些晦涩难懂且难以调试,但一些最常见的原因包括:

变量被中断修改

//---in main()---
unint8_t rxByte = 0;
printf("%d", rxByte);   //prints "0"

//---later in Uart0_Rx_Handler()---
rxByte = U0RXREG;       //rxByte set to (for example) 55

//---later in main()---
printf("%d", rxByte);   //still prints "0"!!!

如果变量被中断处理程序修改,则需要声明它volatile。 Volatile 让编译器知道该变量可以被异步修改,并且它不应该使用寄存器中的缓存副本。

//---in main()---
volatile unint8_t rxByte = 0;
printf("%d", rxByte);   //prints "0"

//---later in Uart0_Rx_Handler()---
rxByte = U0RXREG;       //rxByte set to 55

//---later in main()---
printf("%d", rxByte);   //corectly prints 55

超出数组的界限

C 中没有检查来防止您超出数组的范围。

int array[10];
int my_var = 55;

printf("%d", my_var);   //prints "55"
for(i=0; i<11; i++)   // eleven is one too many indexes for this array
{
  array[i] = i;
}
printf("%d", my_var);   // prints "11"!!!

在这种情况下,我们循环了 11 次,比数组大一个索引。在大多数编译器中,这将导致覆盖在数组之后声明的变量(页面上的任何地方,它们甚至不必在下一行声明)。这种情况可能发生在许多不同的情况下,包括多维数组和堆栈损坏。

忘记取消引用指针

虽然微不足道,但在赋值时忘记指针上的星号不会正确设置变量

int* pCount;
pCount = 10;   //forgot the asterisk!!!
printf("%d", *pCount);   //prints ??

屏蔽同名变量

在内部范围内重用变量名(例如在 if/for/while 块内或函数内)会在别处隐藏同名的变量。

int count = 10;   //count is 10
if(byteRecevied)
{
  int count = U0RXREG;   //count redeclared!!!
  DoSomething(count); 
  printf("%d", count);   //prints "55"
}
printf("%d", count);   //prints "10"

【讨论】:

    【解决方案2】:

    我想为 Zack 的出色回答添加另一个可能的原因。

    优化

    这个经常让我吃惊。一个好的优化编译器会注意到两个不同的变量从不同时使用,并且会通过在内存中为这些变量提供相同的地址来优化程序。当您单步执行代码时,您可能会在监视窗口中看到一个明显变化的变量。但真正发生的是共享其地址的变量正在被写入。

    编译器的另一个技巧是简单地删除它认为没有必要的变量。有时您可能会在代码中执行与此等效的操作:

    force_a = mass_a * acceleration_a
    force_b = mass_b * acceleration_b
    total_force = force_a + force_b
    

    编译器发现没有真正需要变量force_a和force_b,因此将代码更改为:

    total_force = (mass_a * acceleration_a) + (mass_b * acceleration_b)
    

    您永远不会看到 force_a 和 force_b 正在更新,但您仍然可以将它们添加到监视窗口。

    当我单步执行我的程序时,我确信某个变量或其他变量中有错误的值,但是当我让我的程序不单步执行时,它似乎可以工作。检查您是否没有发生这种情况。

    添加:

    正如 Ashish Kulkarni 所说,您可以通过关闭优化来检查这一点。

    【讨论】:

    • 正确使用“volatile”应该可以解决许多此类优化问题。只是警告编译器,“是的,这是一个真正的变量,我向你保证这个值可以改变,但你只是看不到它。”
    • 是的。优化是这种行为的主要原因之一。如果您在回答中提到 可以 在大多数 IDE 和 gcc 中禁用优化以便可以解决此问题,这将有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-04-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多