强制ARM编译器发出未定义的宏错误

时间:2017-02-06 17:25:09

标签: c arm c-preprocessor keil armcc

头文件config.h包含以下语句:

#define RED 0
#define BLUE 1
#define GREEN 2
#define CONFIG_COLOR RED

源文件main.c 包含config.h但包含以下内容:

#if CONFIG_COLOR == RED
/* Red code */
#elif CONFIG_COLOR == BLUE
/* Blue code */
#elif CONFIG_COLOR == GREEN
/* Green code */
#endif

ARM编译器ARMCC(或更确切地说,C预处理器)在编译main.c时不会发出任何警告或错误,尽管未定义CONFIG_COLOR

有没有办法强制编译器在上述情况下发出错误?

或者,有没有办法强制Keil ARM uVision IDE始终为每个源文件包含config.h

我知道在GCC中有标志可以做到这两点。

2 个答案:

答案 0 :(得分:1)

每当在#if / #elif指令中未定义符号时,它就会被0替换。因此,如果没有定义CONFIG_COLOR,则代码与:

相同
#if 0 == RED
/* Red code */
#elif 0 == BLUE
/* Blue code */
#elif 0 == GREEN
/* Green code */
#endif

例如,如果将RED定义为0,则会导致可怕的错误,因此第一个条件变为真。如果CONFIG_COLOR未定义#error,则可以有条件地暂停编译并显示错误:

#ifndef CONFIG_COLOR
    #error CONFIG_COLOR is not defined!
#endif

你也可以给GCC / Clang -Wl,-Wundef选项在发生这种情况时发出警告。这可以通过-Wl,-Werror选项变成一个完整的错误。

答案 1 :(得分:1)

总之,基本问题似乎是armcc C预处理器/编译器没有选项来警告在#if预处理器指令中使用未定义的预处理器宏,以及下游开发人员需要提示才能使他们的代码正常工作。

正如我在评论中提到的,我的第一直觉是使用预处理器宏来指示是否选择了颜色,而不是选择了哪种颜色。在这种情况下,代码块变为

#if defined(CONFIG_COLOR_IS_RED)
/* Red case */
#elif defined(CONFIG_COLOR_IS_GREEN)
/* Green case */
#elif defined(CONFIG_COLOR_IS_BLUE)
/* Blue case */
#else
#error config.h is not included!
#endif

当然,下游开发者必须包括整个块。 (这似乎是OP的一个问题;下行者可能会忘记或错误编辑该区块。)

另一种选择是在表达级别进行选择(与块级别相反);即使用宏

CONFIG_COLOR(red-expression, green-expression, blue-expression)

config.h中定义为,例如

#if   defined(CONFIG_COLOR_IS_RED)
#define CONFIG_COLOR(red, green, blue) (red)
#elif defined(CONFIG_COLOR_IS_GREEN)
#define CONFIG_COLOR(red, green, blue) (green)
#elif defined(CONFIG_COLOR_IS_BLUE)
#define CONFIG_COLOR(red, green, blue) (blue)
#else
#error Color not configured!
#endif

在这种情况下,如果未包含头文件,编译器应在编译时警告未声明的符号CONFIG_COLOR,并在链接时拒绝链接,因为符号CONFIG_COLOR未定义。

在这种情况下,用户代码非常简单,例如

my_color_attribute = CONFIG_COLOR( my_red, my_green, my_blue );

或常量或表达式,而不是my_redmy_greenmy_blue。如你所见,宏选择三个中的一个值,具体取决于哪个"颜色"被选中。

如果需要块级代码,那么我建议使用宏

IF_RED
    /* Red case */
ENDIF
IF_GREEN
    /* Green case */
ENDIF
IF_BLUE
    /* Blue case */
ENDIF

其中宏在config.h中定义为例如

#if   defined(COLOR_IS_RED)
#define IF_RED   if (1) {
#define IF_GREEN if (0) {
#define IF_BLUE  if (0) {
#elif defined(COLOR_IS_GREEN)
#define IF_RED   if (0) {
#define IF_GREEN if (1) {
#define IF_BLUE  if (0) {
#elif defined(COLOR_IS_BLUE)
#define IF_RED   if (0) {
#define IF_GREEN if (0) {
#define IF_BLUE  if (1) {
#else
#error Color not selected!
#endif
#define END_IF   }

为未选择的代码案例生成失效代码(永远不会到达的代码);编译器应该能够优化分支,尽管我不确定armcc是否需要/哪些选项。

如果未包含config.h头文件,则编译器会将IF_RED等符号视为未定义。