2

我们目前正在为 msp430 MCU 开发应用程序,并且遇到了一些奇怪的问题。我们发现,在声明“正常”变量之后声明具有范围的数组有时会导致似乎未定义的行为。像这样:

foo(int a, int *b);

int main(void)
{
    int x = 2;
    int arr[5];

    foo(x, arr);

    return 0;
}

foo 作为第二个变量传递一个指针,该指针有时不指向arr数组。我们通过单步执行程序来验证这一点,发现主作用域中的 arr array-as-a-pointer 变量的值与 foo 作用域中的 b 指针变量的值不同。不,这不是真正可复制的,我们只是偶尔观察到这种行为。

这甚至在执行 foo 函数的单行之前就可以观察到,传递的指针参数 (b) 根本没有指向 arr 所在的地址。

更改示例似乎可以解决问题,如下所示:

foo(int a, int *b);

int main(void)
{
    int arr[5];
    int x = 2;

    foo(x, arr);

    return 0;
}

是否有人对我们为什么会遇到这种行为有任何意见或提示?或者类似的经历?MSP430 编程指南指定代码应符合 ANSI C89 规范。所以我想知道它是否说必须在非数组变量之前声明数组?

对此的任何意见将不胜感激。


更新

@Adam Shiemke 和 tomlogic:

我想知道 C89 对在声明中初始化值的不同方式有什么规定。你是否允许写类似的东西:

int bar(void)
{
    int x = 2;
    int y;

    foo(x);
}

如果是这样,那又如何:

int bar(int z)
{
    int x = z;
    int y;

    foo(x);
}

这是允许的吗?我假设以下内容一定是非法的 C89:

int bar(void)
{
    int x = baz();
    int y;

    foo(x);
}

提前致谢。


更新 2 问题已解决。基本上,我们在调用函数(foo)之前和声明变量之后禁用中断。我们可以在一个简单的示例中重现该问题,解决方案似乎是在禁用中断调用之后添加一个 _NOP() 语句。

如果有人有兴趣,我可以发布重现问题的完整示例,以及修复?

感谢您对此的所有意见。

4

7 回答 7

3

这看起来像一个编译器错误。

如果您使用第一个示例(有问题的示例)并将函数调用编写为foo(x, &arr[0]);,您会看到相同的结果吗?如果你像这样初始化数组int arr[5] = {0};呢?这些都不应该改变任何东西,但如果他们这样做,就会暗示编译器错误。

于 2010-03-25T16:28:08.120 回答
3

在您更新的问题中:

基本上,我们在调用函数(foo)之前和声明变量之后禁用中断。我们可以在一个简单的示例中重现该问题,解决方案似乎是_NOP()在禁用中断调用之后添加一条语句。

听起来好像中断禁用内在/功能/宏(或者中断被禁用)可能会导致指令被“跳过”或其他东西。我会调查它是否编码/工作正常。

于 2010-03-28T18:09:55.910 回答
2

这两个例子看起来都符合我的 C89。假设foo没有超出数组边界的访问,行为应该没有明显的差异。

于 2010-03-25T11:38:29.037 回答
2

对于 C89,变量需要在任何赋值之前在范围开始处的列表中声明。C99 允许您混合赋值和声明。所以:

{ 
    int x; 
    int arr[5];

    x=5;
...

是合法的 c89 样式。如果它不支持 c99,我很惊讶你的编译器没有抛出某种错误。

于 2010-03-25T16:13:37.930 回答
2

您应该能够根据生成的汇编代码确定它是否是编译器错误。当您更改变量声明的顺序时,程序集会有所不同吗?如果您的调试器允许,请尝试单步执行程序集。

如果您确实发现了编译器错误,请检查您的优化。我已经看到优化器引入了这样的错误。

于 2010-03-25T21:59:46.893 回答
2

假设真正的代码要复杂得多,这是我要检查的一些事情,请记住它们是猜测:

你有时会溢出堆栈吗?如果是这样,这可能是编译器/uC 的“堆栈防御”的一些神器吗?&foo 的错误值是否落在可预测的内存范围内?如果是这样,该范围是否有任何意义(在堆栈内等)?

mcu430 的 ram 和 rom 寻址范围是否不同?也就是说,ram 的地址空间是 16 位,而程序地址空间是 24 位?例如,PIC 就有这样的架构。如果是这样,将 arr 分配为 rom(24 位)并且函数期望指向 ram(16 位)的指针是可行的.

于 2010-03-26T18:47:38.947 回答
1

也许您在程序中的某个地方存在非法内存写入,这会破坏您的堆栈。

拆机看了吗?

于 2010-03-25T12:47:13.823 回答