在“正常”之前声明数组c中的变量?
我们目前正在为 msp430 MCU 开发一个应用程序,但遇到了一些奇怪的问题。我们发现,在声明“正常”变量之后声明具有作用域的数组有时会导致看似未定义的行为。像这样:
foo(int a, int *b);
int main(void)
{
int x = 2;
int arr[5];
foo(x, arr);
return 0;
}
foo 被传递一个指针作为第二个变量,有时不指向 arr 数组。我们通过单步执行程序来验证这一点,并看到主作用域中的 arr 数组作为指针变量的值与 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() 语句。
如果有人感兴趣,我可以发布重现问题的完整示例以及修复方法?
感谢您对此的所有意见。
We are currently developing an application for a msp430 MCU, and are running into some weird problems. We discovered that declaring arrays withing a scope after declaration of "normal" variables, sometimes causes what seems to be undefined behavior. Like this:
foo(int a, int *b);
int main(void)
{
int x = 2;
int arr[5];
foo(x, arr);
return 0;
}
foo is passed a pointer as the second variable, that sometimes does not point to the arr array. We verify this by single stepping through the program, and see that the value of the arr array-as-a-pointer variable in the main scope is not the same as the value of the b pointer variable in the foo scope. And no, this is not really reproduceable, we have just observed this behavior once in a while.
This is observable even before a single line of the foo function is executed, the passed pointer parameter (b) is simply not pointing to the address that arr is.
Changing the example seems to solve the problem, like this:
foo(int a, int *b);
int main(void)
{
int arr[5];
int x = 2;
foo(x, arr);
return 0;
}
Does anybody have any input or hints as to why we experience this behavior? Or similar experiences? The MSP430 programming guide specifies that code should conform to the ANSI C89 spec. and so I was wondering if it says that arrays has to be declared before non-array variables?
Any input on this would be appreciated.
Update
@Adam Shiemke and tomlogic:
I'm wondering what C89 specifies about different ways of initializing values within declarations. Are you allowed to write something like:
int bar(void)
{
int x = 2;
int y;
foo(x);
}
And if so, what about:
int bar(int z)
{
int x = z;
int y;
foo(x);
}
Is that allowed? I assume the following must be illegal C89:
int bar(void)
{
int x = baz();
int y;
foo(x);
}
Thanks in advance.
Update 2
Problem solved. Basically we where disabling interrupts before calling the function (foo) and after declarations of variables. We where able to reproduce the problem in a simple example, and the solution seems to be to add a _NOP() statement after the disable interrupt call.
If anybody is interested I can post the complete example reproducing the problem, and the fix?
Thanks for all the input on this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这看起来像是一个编译器错误。
如果您使用第一个示例(有问题的示例)并将函数调用编写为
foo(x, &arr[0]);
,您会看到相同的结果吗?如果像int arr[5] = {0};
这样初始化数组会怎么样?这些都不会改变任何东西,但如果它们改变了,就会暗示编译器错误。That looks like a compiler bug.
If you use your first example (the problematic one) and write your function call as
foo(x, &arr[0]);
, do you see the same results? What about if you initialize the array likeint arr[5] = {0};
? Neither of these should change anything, but if they do it would hint at a compiler bug.在您更新的问题中:
听起来好像中断禁用内部/函数/宏(或者无论如何禁用中断)可能会导致指令被“跳过”或其他情况。我会调查它是否编码/工作正常。
In your updated question:
It sounds as if the interrupt disabling intrinsic/function/macro (or however interrupts are disabled) might be causing an instruction to be 'skipped' or something. I'd investigate whether it is coded/working correctly.
您应该能够根据生成的汇编代码确定这是否是编译器错误。当您更改变量声明的顺序时,程序集是否会有所不同?如果您的调试器允许,请尝试单步执行程序集。
如果您确实发现编译器错误,也请检查您的优化。我见过优化器引入的这样的错误。
You should be able to determine if it is a compiler bug based on the assembly code that is produced. Is the assembly different when you change the order of the variable declarations? If your debugger allows you, try single stepping through the assembly.
If you do find a compiler bug, also, check your optimization. I have seen bugs like this introduced by the optimizer.
对我来说,这两个示例看起来都符合 C89。假设
foo
没有访问超出数组范围的内容,那么行为上应该没有明显的差异。Both examples look to be conforming C89 to me. There should be no observable difference in behaviour assuming that
foo
isn't accessing beyond the bounds of the array.对于 C89,在进行任何赋值之前,需要在作用域开始处的列表中声明变量。 C99 允许您混合赋值和声明。所以:
是合法的c89风格。我很惊讶你的编译器在不支持 c99 的情况下没有抛出某种错误。
For C89, the variables need to be declared in a list at the start of the scope prior to any assignment. C99 allows you to mix assignment an declaration. So:
is legal c89 style. I'm surprised your compiler didn't throw some sort of error on that if it doesn't support c99.
假设真实的代码要复杂得多,这是我要检查的一些事情,请记住它们是猜测:
您有时会溢出堆栈吗?如果是这样,这可能是编译器/uC 的“堆栈防御”的某种产物吗? &foo 的错误值是否落入可预测的内存范围内?如果是这样,该范围是否有任何意义(在堆栈内等)?
mcu430 的 ram 和 rom 寻址范围是否不同?也就是说,ram的地址空间是16bit,而程序地址空间是24bit?例如,PIC 就具有这样的架构。如果是这样,则 arr 被分配为 rom(24 位)并且该函数需要一个指向 ram(16 位)的指针,当 arr 被分配在地址空间的前 16 位中时,代码将工作,但如果其高于该范围,则会变砖。
Assuming the real code is much more complex, heres some things i would check, keep in mind they are guesses:
Could you be overflowing the stack on occasion? If so could this be some artifact of "stack defense" by the compiler/uC? Does the incorrect value of &foo fall inside a predictable memory range? if so does that range have any significance (inside the stack, etc)?
Does the mcu430 have different ranges for ram and rom addressing? That is, is the address space for ram 16bit while the program address space 24bit? PIC's have such an architecture for example. If so it would be feasible that arr is getting allocated as rom (24bit) and the function expects a pointer to ram (16bit) the code would work when the arr was allocated in the first 16bit's of address space but brick if its above that range.
也许您在程序中的某个位置进行了非法内存写入,这会损坏您的堆栈。
你看过拆解吗?
Maybe you have at some place in your program in illegal memory write which corrupts your stack.
Did you have a look at the disassembly?