条件编译策略——如何避免 C 语言中的未定义符号
Conditional compilation strategies - how to avoid undefined symbols in C
我正在尝试用 C 编写一个模块化项目。
我正在为嵌入式 ARM CPU 编写固件。它由不同的部分组成,由于内存限制,不能同时全部编译。
简化一下,假设我有一个模块 A,它管理固件的所有可选部分,每个部分都在其模块中编码(B、C、D 等...)
在模块 A 中,我使用了#ifdef 子句:
#ifdef USE_B
#include "B.h"
#endif
#ifdef USE_C
#include "C.h"
#endif
...
然后最重要的是,我只是简单地为我想要包含的模块定义关键字。
我在文件 Z.c 中有一些全局变量应该保留在那里。由于我的目标是最大限度地减少内存使用,因此我也将它们的声明附在#ifdef 中
#ifdef USE_B
uint8_t usedonlybyb;
#endif
#ifdef USE_C
uint8_t usedonlybyc;
#endif
...
发生的情况是,即使文件 B 和文件 C 在编译时与项目的其他部分完全断开连接,在编译结束时我会得到 "Undefined symbol" 外部变量错误 "usedonlybyx",禁用模块无法访问。
我想保留在模块 Z 中声明的 usedonlybyx 变量,因为那个是通用设置模块。
是否有一种优雅的方法来抑制这些错误,并且仍然能够在我的范围内取得成功?
我是否应该简单地将整个模块 B、C、...包含在 #ifdef / #endif 中?
更简单的解决方案是将 b.h
和 b.c
文件中的整个实现和声明包含在 #ifdef USE_B
和 #endif
中。其他模块也一样。这样一来,一个模块的所有条件编译都是独立的,不必遍及使用 #include "b.h"
的其他代码。
// b.h
#ifdef USE_B
// declarations and include guards
#endif
// b.c
#ifdef USE_B
// definitions
#endif
// a.c
#include "b.h" // <- no USE_B needed here
您可以尝试将 B 和 C 模块拆分为离散的库组件,确保这些库使用的任何全局变量都包含在其中。这可能需要将变量的 extern
声明移动到库接口文件,或根据需要提供访问器方法。
或者,如果您使用的是 GCC,则编译器具有 __attribute__((weak))
形式的语言扩展,它将声明一个“以防万一,未在其他任何地方定义” ' 使链接器满意的变量版本。
我正在尝试用 C 编写一个模块化项目。 我正在为嵌入式 ARM CPU 编写固件。它由不同的部分组成,由于内存限制,不能同时全部编译。
简化一下,假设我有一个模块 A,它管理固件的所有可选部分,每个部分都在其模块中编码(B、C、D 等...)
在模块 A 中,我使用了#ifdef 子句:
#ifdef USE_B
#include "B.h"
#endif
#ifdef USE_C
#include "C.h"
#endif
...
然后最重要的是,我只是简单地为我想要包含的模块定义关键字。
我在文件 Z.c 中有一些全局变量应该保留在那里。由于我的目标是最大限度地减少内存使用,因此我也将它们的声明附在#ifdef 中
#ifdef USE_B
uint8_t usedonlybyb;
#endif
#ifdef USE_C
uint8_t usedonlybyc;
#endif
...
发生的情况是,即使文件 B 和文件 C 在编译时与项目的其他部分完全断开连接,在编译结束时我会得到 "Undefined symbol" 外部变量错误 "usedonlybyx",禁用模块无法访问。
我想保留在模块 Z 中声明的 usedonlybyx 变量,因为那个是通用设置模块。
是否有一种优雅的方法来抑制这些错误,并且仍然能够在我的范围内取得成功?
我是否应该简单地将整个模块 B、C、...包含在 #ifdef / #endif 中?
更简单的解决方案是将 b.h
和 b.c
文件中的整个实现和声明包含在 #ifdef USE_B
和 #endif
中。其他模块也一样。这样一来,一个模块的所有条件编译都是独立的,不必遍及使用 #include "b.h"
的其他代码。
// b.h
#ifdef USE_B
// declarations and include guards
#endif
// b.c
#ifdef USE_B
// definitions
#endif
// a.c
#include "b.h" // <- no USE_B needed here
您可以尝试将 B 和 C 模块拆分为离散的库组件,确保这些库使用的任何全局变量都包含在其中。这可能需要将变量的 extern
声明移动到库接口文件,或根据需要提供访问器方法。
或者,如果您使用的是 GCC,则编译器具有 __attribute__((weak))
形式的语言扩展,它将声明一个“以防万一,未在其他任何地方定义” ' 使链接器满意的变量版本。