我有以下问题:
我正在为一个与微控制器一起使用的传感器编写一个收集库。意思是我在传感器项目中使用了很多库,并对它们进行了抽象,并在用于学生项目的统一库中对其进行了一些简化。
我使用#define
结构来确定学生要使用和连接哪些传感器。
示例:
#define IR_SENSOR_USED
然后,在库的.h和.cpp文件中,我使用#ifdef
-#endif
对来定义和声明给定传感器以及包含给定库的功能。
我的Sensors.h
文件中的示例:
#ifdef IR_SENSOR_USED
#include "SparkFun_GridEYE_AMG88/src/SparkFun_GridEYE_Arduino_Library.h"
extern GridEYE grideye;
void setup_ir_sensor();
void read_ir_sensor();
void enable_ir_interrupt(float lower, float upper, float hysteresis);
void disable_ir_interrupt();
#endif
以及来自我的Sensors.cpp
文件:
#ifdef IR_SENSOR_USED
void setup_ir_sensor() {
Wire.begin(16, 17, 0x69);
grideye.begin(0x69, Wire);
}
void read_ir_sensor() {
for (int i = 0; i <= 64; i++) {
sensor_values.ir_pixel_temp[i] = grideye.getPixelTemperature(i);
}
sensor_values.ir_device_temp = grideye.getDeviceTemperature();
}
void enable_ir_interrupt(float lower, float upper, float hysteresis) {...}
void disable_ir_interrupt() {...}
#endif
但是,只要我在.cpp文件中有#ifdef
,如果尝试在setup()
中调用该函数,就会出现以下错误:
sketch/Sensors.ino.cpp.o:(.literal._Z5setupv+0xc): undefined reference to `read_ir_sensor()'
sketch/Sensors.ino.cpp.o: In function `setup()':
.../Sensors/Sensors.ino:112: undefined reference to `read_ir_sensor()'
collect2: error: ld returned 1 exit status
exit status 1
如果我将它们注释掉,则代码可以正常执行。同样位于setup_sensors()
和Sensors.h
文件中并且不被.cpp
包围的另一个功能(#ifdef
)也可以正常工作。
这是我的Sensors.ino
草图:
#define IR_SENSOR_USED
//#define COLOR_SENSOR_USED
//#define ENV_SENSOR_USED
//#define TEMP_SENSOR_USED
#include "Sensors.h"
void setup() {
sensor_setup();
read_ir_sensor();
}
void loop() {
}
这是什么原因? (为什么)预处理器不能正确执行.cpp文件中的指令?
答案 0 :(得分:1)
这个问题可能是XY problem的一个实例。
如果您希望库的用户选择他们需要的功能,则将声明放在单独的标头中会更有意义。例如IR_sensor.h
,然后
#define IR_SENSOR_USED
#include "Sensors.h"
仅成为#include "IR_sensor.h"
。
如果需要考虑库的大小,则可以将其拆分为单独的库。
第三个选项是提供作为header-only库的功能。
确切答案:
这是什么原因? (为什么)预处理器不执行 .cpp文件中的指令正确?
最可能的原因是Sensors.cpp
不知道#define IR_SENSOR_USED
。定义在另一个未包含的文件中。
即使IR_SENSOR_USED
将在Sensors.cpp
中定义,也会出现另一个问题:必须为定义的每种可能的组合重新编译Sensors.cpp
。否则,ifdefed代码将从编译中排除,并且不能通过调用#define
在客户端简单地启用。
答案 1 :(得分:1)
正如评论和其他答案所指出的那样,任何int
伪指令仅在包含它们的文件中可见。因此拥有
#define
#define IR_SENSOR_USED
中的不会影响任何未在Sensors.cpp
中编译的代码(重要的是,它将影响Sensors.cpp
中包含的.h
文件中包含的代码Sensors.cpp
。但这不会影响其他#define
文件中包含的任何内容。
比Arduino更复杂的构建环境具有更好,更复杂的方法来解决此问题,但是Arduino世界并没有为您提供很多工具来处理此问题。
我在Arduino世界中所做的只是拥有一个名为.cpp
的文件,其中包含我在项目范围内需要的所有config.h
语句。我#define
在每个需要这些值的文件中。
因此,在您的情况下,您将在#include "config.h"
中使用所有定义,然后在依赖于每个文件的每个文件的开始处config.h
中使用哪个设备。
您甚至可以将其包含在#include "config.h"
文件的开头。我会考虑将两个文件分开,以便在需要配置的内容和有用的代码之间有明确的界限。
我还将所有敏感值(wifi凭据,密码,API密钥)保留在此文件中,并将其从我在Github上发布的代码中排除。在其中,我包括一个“ config-example.h”文件,其中包含所有指令,但带有伪值,以便其他使用该代码的人可以对其进行编辑和重命名。