我是否正在使用预处理器?

时间:2015-01-19 03:08:19

标签: c gcc file-io c-preprocessor name-clash

请注意:这不是作业。该程序不完整,并没有完全发挥作用,但至少应该编译。

我正处于使用C Primer Plus Book的自学过程中(简而言之,我是C的新手)。我几乎已经完成了对整本书的阅读,并且已经完成了每一章的练习,并且我不时地完成了切线。这是其中一次。我遇到了一个特殊的问题,我很确定这与预处理程序指令有关。

我正在使用MinGW(gcc for windows)并报告:

  

gcc报告的错误是:

     

nanfunct.c:'关键字的多重定义'
  nanite.c:首先在此定义
  等......等......更多错误......

我很确定这是由于包含多个头文件引起的,但更重要的是我创建然后包含的头文件导致了这个问题。

这个问题似乎与指向char-arrays(或基于字符串的数组)有关,这些数组在编译时是重复的,即使我说只有在尚未预定义的情况下才定义它。

例如:

#ifndef MENU_OPTIONS
#   define MENU_OPTIONS ON
#   if MENU_OPTIONS == ON
        ...some code here...

        char * keywords[] = {
            "copy", "help", "line",
            "quit", "read", "write"
        };

        char * keyletters[] = {
            "c", "h", "l",
            "q", "r", "w"
        };
#   endif
#endif
  

我使用的是三个文件:

     

nanite.c - > main()的源文件
  nanfunct.c - >功能的源文件
  nanproto.h - > nanite.c和nanfunct.c的头文件

nanite.c nanfunct.c 内部 #include nanproto.h

  

在pastebin上发布的源文件:
  nanproto.h - > nanite.c nanfunct.c 的头文件   nanite.c& nanfunct.c - >源文件

为什么会这样?我认为 #ifndef 应该让这样的事情发生吗?

2 个答案:

答案 0 :(得分:4)

您误解了预处理器的功能,或者C源文件的编译和链接方式。

每个源文件都是单独预处理的。因此,在预处理之后,nanfunct.c包含keywordskeyletters的定义。然后将预处理的源编译到目标文件nanfunct.o。

预处理后,nanite.c还包含keywordskeyletters的定义。编译此预处理源以生成目标文件nanite.o。

然后链接器尝试将nanfunct.o和nanite.o结合起来。它发现keywordskeyletters有多个定义,因此它会显示错误消息并中止。

如果您希望在多个源文件中提供某些内容,通常的模式是将声明放在头文件中,并将定义放在一个源文件中。

移动它:

char * keywords[] = {
        "copy", "help", "line",
        "quit", "read", "write"
};

char * keyletters[] = {
        "c", "h", "l",
        "q", "r", "w"
};

进入nanite.c nanfunct.c(不是两者)。将这些声明添加到nanite.h:

extern char * keywords[];
extern char * keyletters[];

这样,定义只包含在一个目标文件中。

请注意,这仅适用于全局变量和函数。它不适用于结构,联合,枚举或typedef,因为它们不包含在目标文件中。

答案 1 :(得分:2)

您通过在.h文件中添加定义来犯错误。只有声明进入.h文件。

如果你把它(一个定义):

char * keywords[] = { "foo" };
<。>在.h文件中,然后将其包含在多个C文件中,您使用的#ifdef类型无关紧要,您仍将最终定义定义的变量在项目的多个位置。

要记住的关键是每个.c文件都是独立于其他文件编译的。这意味着,如果您#define在另一个C文件中发送某些内容并不重要。

你的.h文件应该是这样的:

extern char *keywords[];

然后一个 .c文件应提供定义。