Gcc Cortex-M编译器生成不正确的FOR循环
在Cortex-M 4和Cortex-M 0上测试和复制。 我发现GCC编译器有一个问题。当一个函数被声明为int类型(非void),并且包含for循环,但没有return语句时,for循环不会中断;在反汇编代码之后,有返回和无返回的函数之间存在差异 编译此代码时,不会抛出错误消息。在第一次编译时,会抛出一个关于缺少return语句的警告,但在这之后,该警告将不会再次出现,直到您重新启动IDE。如此严重的问题可能无法编译,或者至少使Arduino崩溃,但它永远不会脱离for循环 我主要是想找到适当的渠道来报告这一点,因为我不确定是否launchpad或是否继续维护。如果有人知道哪个站点(或两者)仍在维护中,或者如果有人直接与项目中的某个人联系,我可以与他分享,请分享 下面是对该行为更全面的描述 Arduino代码Gcc Cortex-M编译器生成不正确的FOR循环,gcc,arm,undefined-behavior,cortex-m,compiler-bug,Gcc,Arm,Undefined Behavior,Cortex M,Compiler Bug,在Cortex-M 4和Cortex-M 0上测试和复制。 我发现GCC编译器有一个问题。当一个函数被声明为int类型(非void),并且包含for循环,但没有return语句时,for循环不会中断;在反汇编代码之后,有返回和无返回的函数之间存在差异 编译此代码时,不会抛出错误消息。在第一次编译时,会抛出一个关于缺少return语句的警告,但在这之后,该警告将不会再次出现,直到您重新启动IDE。如此严重的问题可能无法编译,或者至少使Arduino崩溃,但它永远不会脱离for循环 我主要是想找到适
=============
这是一个最小可复制示例的尝试。在较大的项目中,我曾在两个不同的场合遇到过这个问题,这会导致程序以非常意外和难以调试的方式运行(但总是通过在函数定义中添加return语句来修复)
int-affunctionnoreturn(int计数)
{
42f8:b538推动{r3,r4,r5,lr}
连续打印(“CountNR”);
42fa:4909 ldr r1,[pc,#36];(4320)
序列号.println(计数);
对于(int i=0;i也许能说的最有帮助的事情是:“为什么你想错过返回语句?你希望实现什么?”
各种语言标准(Arduino有点像C++但有一些有趣的预处理)告诉你如果你写了有效的代码会发生什么。他们并不总是告诉你如果你写了无效的代码会发生什么。在这种情况下,编译器已经非常有帮助地指出了你的代码错误的原因,但是在那之后,它完全可以自由地做任何事情。无论它做什么,这都不是编译器中的错误,而是代码中的错误。这它有时被称为“垃圾输入-垃圾输出”
为了解释为什么会得到这样的结果,可以这样想:编译器知道在一个有效的程序中,如果没有return语句,执行永远不会运行到函数的末尾,因此如果循环后没有return语句,可以安全地假设它永远不会离开循环优化有效代码以更快地运行。如果此假设改变了无效程序的功能,则编译器作者通常不关心。他们通常只关心有效程序的功能
(关于launchpad页面,如果您单击页面顶部的大链接,您将看到一条关于站点移动到何处的消息).您使用的编译器选项是什么?会抛出缺少的返回语句,但之后警告将不会再次出现,直到您重新启动IDE。
这与您的IDE有关。您是否能够使用更简单的代码重新创建行为,而不使用Arduino库?在Cortex-M 4和Cortex-M 0上复制。
因此我们知道Cortex你在使用什么控制器?请提供更多信息。一个最小的可复制示例,gcc版本,命令行选项,摆脱库调用并用其他东西替换它们,等等。我还可以复制这个。请使用objdump-d而不是gdbit。很明显,工具链仍在维护中,当前版本,具有返回路径的生成。请提供一个可重复的、最小的示例。请三次检查代码是否实际编译且没有错误。int-affunctionnoreturn()
应声明为void-affunctionnoreturn()
相反,因为它不会返回任何内容。GCC错误通常取决于版本。我们最近使用较旧的7-2017-q4编译器进行了测试,它的功能与预期一致(没有功能流问题).当为标准Arduino Mega 2560编译代码时,代码也以这种方式运行,因此它仅限于Cortex M编译器。我们还测试了这两个函数:当调用FunctionNoForNoreturn(5)时,输出如下:CountNoForNR5 CountNoForWR0这里发生的是程序执行FunctionNoForNoreturn(),然后流入functionNoForWithReturn(),然后由于堆栈混乱而崩溃。intaFunctionNoForNoreturn(int count){Serial.print(“CountNoForNR”);Serial.println(count);delay(1000);}intaFunctionNoForWithReturn(int count){Serial.print(“CountNoForWR”);Serial.println(count);delay(1000);return(count);})
它始终按预期运行。运行到下一个函数是预期的行为。崩溃是预期的行为。您的程序显示未定义的行为。这意味着您必须预期它可以做任何事情。即使它打印出“我是一条鱼”,上下跳跃并着火,这仍然是您应该期望的正确行为。尝试在谷歌搜索“未定义的行为”在C++中,如果调用方会使用返回值,函数只需要返回一个值。尽管现代风格有利于返回值,即使在不需要这样做时,在许多实现中,函数的结尾也会稍微快一些。空函数作为UB,用C和C++编写的函数集合混合使用,可以有效地处理函数的定义,其功能是用一种语言定义的,而不是用另一种语言定义的函数。
/*
gcc compiler error demonstration for Adafruit GrandCentral
gcc version: gcc version 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599] (GNU Tools for Arm Embedded Processors 9-2019-q4-major)
Arduino IDE: all warinings on
Arduino IDE version 1.8.13
Adafruit SAMD version 1.8.11
based on Blink
modified to call two functions which are identical except one does not have a return
statement even though it is of return type int.
In the list file, myList.GrandCentral.lst ,AFunctionWithReturn shows both the comparison of
i with Count and the conditional comparison i>7 with break assembly instructions
The AFunctionNoReturn does not show any assembly instructions for the end of
loop comparision or the conditional comparison i>7 with break
Found 4/8/21 Robert Calay and Tristan Calay
Turns an LED on for one second, then off for one second, repeatedly.
Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
the correct LED pin independent of which board is used.
If you want to know what pin the on-board LED is connected to on your Arduino
model, check the Technical Specs of your board at:
https://www.arduino.cc/en/Main/Products
modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
modified 8 Sep 2016
by Colby Newman
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Blink
*/
#define MAIN
//#include "Serial3.h" We are re-directing serial port output to SERCOM 5 on the Grand Central M4.
int AFunctionWithReturn(int count)
{
Serial.print("CountWR");
Serial.println(count);
for(int i=0;i<count;i++) {
Serial.println(i);
if (i>7)
break;
}
return(1);
}
int AFunctionNoReturn(int count)
{
Serial.print("CountNR");
Serial.println(count);
for(int i=0;i<count;i++) {
Serial.println(i);
if (i>7)
break;
}
//Note: No return statement here.
}
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
AFunctionWithReturn(10); //This loops 8 times
AFunctionNoReturn(10); //This loops forever, never reaching loop()
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
/*
OUTPUT ON ADAFRUIT GRANDCENTRAL SERIAL PORT
CountWR10
0
1
2
3
4
5
6
7
8
CountNR10
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
DOES NOT STOP CONTINUES 2000000+
*
*
*/
int AFunctionWithReturn(int count)
{
42bc: b570 push {r4, r5, r6, lr}
Serial.print("CountWR");
42be: 490c ldr r1, [pc, #48] ; (42f0 <_Z19AFunctionWithReturni+0x34>)
Serial.println(count);
for(int i=0;i<count;i++) {
Serial.println(i);
42c0: 4e0c ldr r6, [pc, #48] ; (42f4 <_Z19AFunctionWithReturni+0x38>)
{
42c2: 4605 mov r5, r0
Serial.print("CountWR");
42c4: 480b ldr r0, [pc, #44] ; (42f4 <_Z19AFunctionWithReturni+0x38>)
42c6: f000 fafa bl 48be <_ZN5Print5printEPKc>
Serial.println(count);
42ca: 480a ldr r0, [pc, #40] ; (42f4 <_Z19AFunctionWithReturni+0x38>)
42cc: 220a movs r2, #10
42ce: 4629 mov r1, r5
42d0: f000 fb43 bl 495a <_ZN5Print7printlnEii>
for(int i=0;i<count;i++) {
42d4: 2400 movs r4, #0
42d6: 42ac cmp r4, r5
42d8: da08 bge.n 42ec <_Z19AFunctionWithReturni+0x30>
Serial.println(i);
42da: 220a movs r2, #10
42dc: 4621 mov r1, r4
42de: 4630 mov r0, r6
42e0: f000 fb3b bl 495a <_ZN5Print7printlnEii>
if (i>7)
42e4: 2c08 cmp r4, #8
42e6: d001 beq.n 42ec <_Z19AFunctionWithReturni+0x30>
for(int i=0;i<count;i++) {
42e8: 3401 adds r4, #1
42ea: e7f4 b.n 42d6 <_Z19AFunctionWithReturni+0x1a>
break;
}
return(1);
}
int AFunctionNoReturn(int count)
{
42f8: b538 push {r3, r4, r5, lr}
Serial.print("CountNR");
42fa: 4909 ldr r1, [pc, #36] ; (4320 <_Z17AFunctionNoReturni+0x28>)
Serial.println(count);
for(int i=0;i<count;i++) {
Serial.println(i);
42fc: 4d09 ldr r5, [pc, #36] ; (4324 <_Z17AFunctionNoReturni+0x2c>)
{
42fe: 4604 mov r4, r0
Serial.print("CountNR");
4300: 4808 ldr r0, [pc, #32] ; (4324 <_Z17AFunctionNoReturni+0x2c>)
4302: f000 fadc bl 48be <_ZN5Print5printEPKc>
Serial.println(count);
4306: 4621 mov r1, r4
4308: 4806 ldr r0, [pc, #24] ; (4324 <_Z17AFunctionNoReturni+0x2c>)
430a: 220a movs r2, #10
430c: f000 fb25 bl 495a <_ZN5Print7printlnEii>
for(int i=0;i<count;i++) {
4310: 2400 movs r4, #0
Serial.println(i);
4312: 4621 mov r1, r4
4314: 220a movs r2, #10
4316: 4628 mov r0, r5
4318: f000 fb1f bl 495a <_ZN5Print7printlnEii>
for(int i=0;i<count;i++) {
431c: 3401 adds r4, #1
431e: e7f8 b.n 4312 <_Z17AFunctionNoReturni+0x1a>
4320: 00006538 .word 0x00006538
4324: 2000011c .word 0x2000011c
00004328 <loop>:
AFunctionWithReturn(10);
AFunctionNoReturn(10);
}