【问题标题】:Force ARM compiler to issue an undefined macro error强制 ARM 编译器发出未定义的宏错误
【发布时间】:2017-06-23 17:50:52
【问题描述】:

头文件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 中有两个标志可以做到。

【问题讨论】:

  • 您确定main.c 不包括something 包括config.h
  • @EugeneSh。 100% 确定。
  • 您可以使用#if !defined(CONFIG_COLOR)#error CONFIG_COLOR is not defined!#endif来检查CONFIG_COLOR是否为预定义宏。
  • 看看here。特别是“不是宏的标识符,它们都被认为是数字零。这允许您编写#if MACRO 而不是#ifdef MACRO,如果您知道宏在定义时将始终具有非零值. 没有函数调用括号的类函数宏也被视为零。“所以不,你不能“强制”它。只写一些额外的条件。
  • 我完全同意 Eugene Sh。更多。因此,如果 REDGREENBLUE 被定义为大于零的唯一整数,那么您可以使用 #if defined(CONFIG_COLOR)#if CONFIG_COLOR-0 == RED-0/* Red case */#elif CONFIG_COLOR-0 == GREEN-0/* Green case */、@987654346 @、/* Blue case */#else#error Invalid CONFIG_COLOR#endif#else#error CONFIG_COLOR is not defined!#endif

标签: c arm c-preprocessor keil armcc


【解决方案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 等符号阻塞为未定义。

【讨论】:

  • 这是微妙的技巧。他们肯定会解决这个问题,但他们抛出看似随机的语法错误会很有趣。
  • @KemyLand:“看似随机的语法错误”是什么意思?不包含config.h 的情况会产生非常明显的编译器警告和链接时错误消息。如果config.h 已经包含在内,则可以期望用户阅读文档,其中明确提及误用会出现什么样的错误消息。老实说,我在这里没有看到任何“看似随机的”。而且,如果下游开发人员真的那么不可靠,我会说这些甚至不是 "hacks" ,只是填充线索。
  • @NominalAnimal 谢谢你的回答。我仍然不确定哪个是更好的解决方案。如果没有定义CONFIG_COLOR,也许最终我会添加一个#error...
  • @NominalAnimal:到目前为止,您显示的代码没有“看似随机的语法错误”。请原谅我,因为我没有试图这么说。相反,我的意思是,例如,从#defines 之一中删除左括号会导致难以发现的语法错误。
  • @KemyLand:我不介意批评,我只想知道确切的细节,以便确定如何解决所引用的问题。我确实犯了很多错误,你看。现在,据我了解,那些#defines 将在config.h 文件中,不应该被下游开发人员修改。事实上,它们甚至可以驻留在另一个文件中,一个内部头文件 #included 由 config.h 编写,顶部有一个很大的注释,上面写着 “把你的手套放在这个文件上,内部的东西!” i>.
【解决方案2】:

只要一个符号没有在#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 选项变成一个全面的错误。

【讨论】:

  • 正如我在 cmets 中对原始问题所写的那样,我知道这是可能的,但这样程序员必须不要忘记放置#error 指令。在这种情况下,我更喜欢编译器(它显然具有必要的知识)来通知程序员。在 GCC 中这是可能的。
  • 如何在 GCC 中是可能的?
  • @s7amuser:查看我的编辑。 GCC 可以选择这样做。
  • @KemyLand 谢谢,我知道 GCC 有这个选项。
  • 我明白了。通过谷歌搜索,armcc 似乎没有类似的选项。
猜你喜欢
  • 1970-01-01
  • 2014-09-07
  • 2015-09-23
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多