【问题标题】:How to fix a compiler error that should be excluded by a preprocessor directive between #ifdef?如何修复应由 #ifdef 之间的预处理器指令排除的编译器错误?
【发布时间】:2023-02-26 00:51:42
【问题描述】:

我有一个可以在 MacOS 和 Linux 上编译的程序。在我的 makefile 中,我定义了一个变量:

# MAC
ifeq ($(UNAME), Darwin)
OS          = APPLE
    
#LINUX
else
OS          = LINUX
endif
    
INCLUDES    = -Iincludes -Ilibft -I$(MLX_DIR) -D$(OS)

导致以下编译:

gcc -Wall -Wextra -Werror -O3 -Iincludes -Ilibft -I./minilibx_mms -DAPPLE -c srcs/parser/parser.c -o objs/parser/parser.o
gcc -Wall -Wextra -Werror -O3 -Iincludes -Ilibft -I./minilibx_mms -DAPPLE -c srcs/terminate/gameover_sys.c -o objs/terminate/gameover_sys.o

如您所见,我将 APPLE 作为宏传递,因此当我调用此函数时:

    if (cub->mlx)
    {
        #ifdef LINUX
        mlx_destroy_display(cub->mlx);
        #endif
        free(cub->mlx);
    }

#ifdef#endif 之间的所有内容都应该在编译前删除,对吗?但是,唉,我从编译器那里得到了这个错误:

Call to undeclared function 'mlx_destroy_display'; ISO C99 and later do not support implicit function declarations clang(-Wimplicit-function-declaration)

该函数仅存在于库的 Linux 实现中。我对预处理器指令的理解哪里不正确?据我了解,当 LINUX 宏不存在时,应删除整个 #ifdef LINUX 部分。

【问题讨论】:

  • 也许您包含的标题之一定义了该宏?
  • 嗨格哈德!我确实注意到现在在标题中我有这个: /* OS CHECK */ #ifdef APPLE #define LINUX 0 #define ESC_KEY 53 但是,我认为将它定义为 0 意味着它是未定义的。显然不是这样?
  • @Hendrik No. 定义它 to 0 表示它是定义的用于#ifdef/#ifndef/#if defined(Macro)支票。但是,如果您改用 #if LINUX,那么未定义和 0 定义的 LINUX 都会导致 #if 分支被删除。 (这就是为什么我个人更喜欢 #if 而不是 #ifdef)。
  • 谢谢大家。你是对的,一个简单的#if LINUX 而不是#ifndef LINUX 就足够了。事后看来,这似乎很明显。
  • @Hendrik 这可能不是很明显。预处理器在其 #if 条件中用 0 替换未定义的标记。所以 #if some_undefined+3 == 3 是一个分支。这就是为什么有时您会看到像 ((int)+OTHER_MACRO) 宏定义这样的转换,这样这些宏也可以在 #if 条件语句中使用,它们变成 ((0)+something)

标签: c c-preprocessor


【解决方案1】:

如何修复应由 #ifdef 之间的预处理器指令排除的编译器错误?

LINUX 是一个非常简单的通用名称,标准头文件或其他项目可能已经定义了它。为您的项目使用唯一的宏前缀。

# Makefile
ifeq ($(UNAME), Darwin)
OS = APPLE
else
OS = LINUX
endif
CFLAGS = -Iincludes -Ilibft -I$(MLX_DIR) -DYOUR_LIBRARY_NAME_OS_$(OS)

# C file
#ifdef YOUR_LIBRARY_NAME_OS_LINUX

【讨论】:

    【解决方案2】:

    另外一个选择:

    检查一个预订的__linux____MACH__ 之类的符号,而不是定义您自己的符号。

    来自GCC's online predefined macros documentation(注:粗体部分):

    C 标准要求所有系统特定的宏都是保留命名空间.所有以两个下划线或一个下划线和一个大写字母开头的名称都保留给编译器和 图书馆随心所欲地使用。然而,历史上特定于系统 宏的名称没有特殊前缀;例如,它是 常见于在 Unix 系统上定义的 unix。对于所有此类宏,GCC 提供一个在开头添加两个下划线的并行宏 和结束。如果unix被定义,__unix__也会被定义。那里 永远不会超过两个下划线; _mips 的并行是 __mips__

    -ansi 选项,或任何 -std 选项要求严格 一致性,被提供给编译器,所有系统特定的 保留命名空间之外的预定义宏被抑制.这 保留名称空间内的并行宏保持定义。

    我们正在慢慢淘汰所有不在 保留命名空间. ...

    通过使用保留符号,您还可以防止名称与第三方标头发生冲突。

    另外,请参阅How do I check OS with a preprocessor directive?

    【讨论】:

      猜你喜欢
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多