对 ifdef 块内函数的未定义引用
undefined reference to function inside ifdef block
我有以下问题:
我正在为一组要与微控制器一起使用的传感器编写一个集合库。这意味着我为一个学生项目使用了很多传感器和抽象库,并在统一库中稍微简化了它们。
我使用 #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文件中的指令?
这个问题可能是 XY problem.
的一个实例
如果您希望库的用户选择他们需要的功能,那么将声明放在单独的 headers 中会更有意义。例如,IR_sensor.h
然后
#define IR_SENSOR_USED
#include "Sensors.h"
变成 #include "IR_sensor.h"
.
如果担心库的大小,可以将其拆分为单独的库。
第三个选项是作为 header-only 库提供功能。
准确答案:
What's the reason for this? (Why) does the preprocessor not execute
the directives in the .cpp file properly?
最可能的原因是 Sensors.cpp
不知道 #define IR_SENSOR_USED
。定义在另一个未包含的文件中。
然而,即使 IR_SENSOR_USED
将在 Sensors.cpp
中定义,也会出现另一个问题:re-compilation of Sensors.cpp
对于每个可能的定义组合都是必要的。否则 ifdefed-code 将被排除在编译之外,并且不能通过调用 #define
.
在客户端简单地启用
正如评论和其他答案所指出的,任何 #define
指令仅在包含它们的文件中可见。所以有
#define IR_SENSOR_USED
in Sensors.cpp
不会影响任何未在 Sensors.cpp
中编译的代码(重要的是,它会影响包含在 .h
文件中的代码 Sensors.cpp
在 #define
之后。但它不会影响其他 .cpp
文件中包含的任何内容。
比 Arduino 更复杂的构建环境有更好、更复杂的方法来处理这个问题,但 Arduino 世界并没有给你很多工具来处理这个问题。
我在 Arduino 世界中所做的只是拥有一个名为 config.h
的文件,其中包含我在项目范围内需要的所有 #define
语句。我 #include "config.h"
在每个需要这些值的文件中。
所以在你的情况下,你会把所有显示在 config.h
和 #include "config.h"
中使用的设备的定义放在依赖它的每个文件的开头。
您甚至可以将其包含在 Sensors.h
文件的开头。我会考虑将这两个文件分开,以便在需要配置的内容和有用代码的内容之间有明确的界限。
我还在这个文件中保留了任何敏感值(wifi 凭据、密码、API 密钥),并将其从我在 Github 上发布的代码中排除。在它的位置,我包含了一个 "config-example.h" 文件,其中包含所有指令,但具有虚拟值,以便其他使用该代码的人可以编辑和重命名它。
我有以下问题:
我正在为一组要与微控制器一起使用的传感器编写一个集合库。这意味着我为一个学生项目使用了很多传感器和抽象库,并在统一库中稍微简化了它们。
我使用 #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文件中的指令?
这个问题可能是 XY problem.
的一个实例如果您希望库的用户选择他们需要的功能,那么将声明放在单独的 headers 中会更有意义。例如,IR_sensor.h
然后
#define IR_SENSOR_USED
#include "Sensors.h"
变成 #include "IR_sensor.h"
.
如果担心库的大小,可以将其拆分为单独的库。
第三个选项是作为 header-only 库提供功能。
准确答案:
What's the reason for this? (Why) does the preprocessor not execute the directives in the .cpp file properly?
最可能的原因是 Sensors.cpp
不知道 #define IR_SENSOR_USED
。定义在另一个未包含的文件中。
然而,即使 IR_SENSOR_USED
将在 Sensors.cpp
中定义,也会出现另一个问题:re-compilation of Sensors.cpp
对于每个可能的定义组合都是必要的。否则 ifdefed-code 将被排除在编译之外,并且不能通过调用 #define
.
正如评论和其他答案所指出的,任何 #define
指令仅在包含它们的文件中可见。所以有
#define IR_SENSOR_USED
in Sensors.cpp
不会影响任何未在 Sensors.cpp
中编译的代码(重要的是,它会影响包含在 .h
文件中的代码 Sensors.cpp
在 #define
之后。但它不会影响其他 .cpp
文件中包含的任何内容。
比 Arduino 更复杂的构建环境有更好、更复杂的方法来处理这个问题,但 Arduino 世界并没有给你很多工具来处理这个问题。
我在 Arduino 世界中所做的只是拥有一个名为 config.h
的文件,其中包含我在项目范围内需要的所有 #define
语句。我 #include "config.h"
在每个需要这些值的文件中。
所以在你的情况下,你会把所有显示在 config.h
和 #include "config.h"
中使用的设备的定义放在依赖它的每个文件的开头。
您甚至可以将其包含在 Sensors.h
文件的开头。我会考虑将这两个文件分开,以便在需要配置的内容和有用代码的内容之间有明确的界限。
我还在这个文件中保留了任何敏感值(wifi 凭据、密码、API 密钥),并将其从我在 Github 上发布的代码中排除。在它的位置,我包含了一个 "config-example.h" 文件,其中包含所有指令,但具有虚拟值,以便其他使用该代码的人可以编辑和重命名它。