gpt4 book ai didi

c++ - 相同代码在不同设备上的不同行为

转载 作者:行者123 更新时间:2023-11-30 00:55:50 25 4
gpt4 key购买 nike

我很困惑。我有一个相同的程序被上传到两个不同的 Arduino 板上。它在 C++ 中。

这是一个更大的程序,但我将其缩减为只有有问题的部分。基本上,我有一个“主机”Arduino 和一个无线通信的“漫游者”Arduino。有多个流动站单元,但问题只发生在其中一个单元上。流动站有需要校准的电机,所以我在我的 Motor 命名空间中有静态变量来保存这些校准值。为避免在每次我想校准它时都必须更改源代码中的这些值、重新编译和重新上传,我使用无线系统允许主机在运行时向流动站发送校准值。

问题是:在一个流动站上,如果我调用 ChangeSpeed 方法,这些值不会更新,但如果我直接修改变量,它们会更新。

我要强调的是,它在五分之四的火星车上运行良好。问题恰好发生在一个流动站上。上传到每个流动站的代码是相同的。

以下代码导致了问题:

电机.h:

namespace Motor
{
static unsigned char left_speed = 0;
static unsigned char right_speed = 0;

void ChangeSpeed(unsigned char, unsigned char);
}

电机.cpp:

void Motor::ChangeSpeed(unsigned char l_speed, unsigned char r_speed)
{
left_speed = l_speed;
right_speed = r_speed;

soft.println("Change speed: " + String(left_speed) + ", " + String(right_speed));
}

主要.cpp:

void UpdateSpeedValuesBad(unsigned char l_speed, unsigned char r_speed)
{
Motor::ChangeSpeed(l_speed, r_speed);
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}

void UpdateSpeedValuesGood(unsigned char l_speed, unsigned char r_speed)
{
Motor::left_speed = l_speed;
Motor::right_speed = r_speed;
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}

void ReturnSpeedValues()
{
soft.println("Motor read: " + String(Motor::left_speed) + ", " + String(Motor::right_speed));
}

案例 1:

bad 流动站上,主机调用UpdateSpeedValuesBad(5, 5),然后调用ReturnSpeedValues。输出是:

Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0

案例 2:

流动站上,主机调用UpdateSpeedValuesGood(5, 5),然后调用ReturnSpeedValues。输出是:

Motor write: 5, 5
Motor read: 5, 5

案例三:

流动站上,主机调用UpdateSpeedValuesBad(5, 5),然后调用ReturnSpeedValues。输出是:

Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5

我做错了什么吗?我来自 C# 背景,所以 C++ 对我来说很陌生。我不知道我是否正在做一些具有未定义行为的事情。


编辑:如果我将所有内容都放入一个文件中,它就可以正常工作。只有当我将它拆分为一个头文件和一个 cpp 文件时,它才会失败。

主要.cpp:

#include <SoftwareSerial.h>

SoftwareSerial soft(9, 10);

namespace Motor
{
static int left_speed = 0;

void ChangeSpeed(unsigned char);
}

void Motor::ChangeSpeed(unsigned char l_speed)
{
left_speed = l_speed;
soft.println("Change speed: " + String(left_speed));
}

void setup()
{
soft.begin(9600);

soft.println("Before: " + String(Motor::left_speed));

Motor::ChangeSpeed(5);
soft.println("Bad attempt: " + String(Motor::left_speed));

Motor::left_speed = 5;
soft.println("Good attempt: " + String(Motor::left_speed));
}

void loop()
{
}

输出:

Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5

编辑 2: 我进入程序集并发现这是一个糟糕的案例。它根据我是调用 ChangeSpeed 还是直接更新值来使用不同的内存地址。有谁知道为什么会这样?是编译器错误还是不能保证地址相同?

000000a8 <setup>:
{
Motor::ChangeSpeed(5, 6);
a8: 85 e0 ldi r24, 0x05 ; 5
aa: 66 e0 ldi r22, 0x06 ; 6
ac: 0e 94 5f 00 call 0xbe ; 0xbe <_ZN5Motor11ChangeSpeedEhh>

Motor::left_speed = 5;
b0: 85 e0 ldi r24, 0x05 ; 5
b2: 80 93 00 01 sts 0x0100, r24

Motor::right_speed = 6;
b6: 86 e0 ldi r24, 0x06 ; 6
b8: 80 93 01 01 sts 0x0101, r24
}
bc: 08 95 ret

000000be <_ZN5Motor11ChangeSpeedEhh>:

void Motor::ChangeSpeed( unsigned char l_speed, unsigned char r_speed )
{
left_speed = l_speed;
be: 80 93 02 01 sts 0x0102, r24
right_speed = r_speed;
c2: 60 93 03 01 sts 0x0103, r22
c6: 08 95 ret

最佳答案

您不应将这些变量设为静态。静态全局变量意味着该变量是编译单元的本地变量(通常是正在编译的 .cpp 文件),因此如果您在头文件中声明了静态变量并将该头文件包含在3 个不同的 .cpp 文件分别编译,那么您将拥有该变量的 3 个独立版本,每个 .cpp 文件一个。

相反,在头文件中将它们声明为

namespace Motor {
extern unsigned char left_speed;
extern unsigned char right_speed;

void ChangeSpeed(unsigned char, unsigned char);
}

这告诉编译器某个文件将为这些变量提供定义并使用该公共(public)共享定义。

然后,由于变量只需要定义一次(这称为 one definition rule),您应该将定义添加到 Motor.cpp:

unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;

我选择 Motor.cpp 来保存定义,因为这是 ChangeSpeed 函数的定义所在。

在 C++ 中,static 关键字的工作方式与在 C# 中有很大不同。在类定义中使用时可能有些相似,但相似之处仅此而已。

关于c++ - 相同代码在不同设备上的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11494827/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com