2

请注意:这不是家庭作业。该程序不完整且功能不完整,但至少应该可以编译。

我正在使用 C Primer Plus Book 进行自学过程(简而言之,我是 C 新手)。我几乎已经读完了整本书,并且一直在完成每一章的练习,有时我会偏离正题。这是其中之一。我遇到了一个特殊的问题,我很确定与预处理器指令有关。

我正在使用 MinGW(Windows 的 gcc),它报告:

gcc 报告的错误是:

nanfunct.c: 'keywords' 的多重定义
nanite.c: 首先在这里定义
等等...等等...更多错误...

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

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

例如:

#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.cnanfunct.c#include nanproto.h

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

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

4

2 回答 2

4

您误解了预处理器的作用,或者 C 源文件是如何编译和链接的。

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

预处理后,nanite.c 还包含keywords和的定义keyletters。这个预处理的源代码被编译生成目标文件 nanite.o。

链接器然后尝试组合 nanfunct.o 和 nanite.o。keywords它发现and的定义不止一个keyletters,因此它显示错误消息并中止。

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

移动这个:

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

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

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

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

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

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

于 2015-01-19T03:14:36.460 回答
2

You're making a mistake by putting definitions in your .h files. Only declarations go in .h files.

If you put this (a definition):

char * keywords[] = { "foo" };

in a .h file, and then include it in multiple C files, it doesn't matter what kind of #ifdefery you use, you will still end up with that variable being defined in multiple places in your project.

The key thing to remember is that each .c file is compiled independently of the others. That means, it doesn't matter if you #defined something in another C file or not.

Your .h file should have something like this:

extern char *keywords[];

And then exactly one .c file should provide the definition.

于 2015-01-19T03:12:04.537 回答