gcc如何处理本地包含的文件?

时间:2016-02-16 04:08:46

标签: c gcc include

这真的不应该是我要问的问题,但不知怎的,我可以通过搜索回答我的问题找不到任何东西。

为了提出另一个问题,我制作了三个文件:main.c,sub.c和sub.h. main.c有'main'函数,而sub.c只包含函数定义。

最初,main.c有'#include'sub.h“'作为唯一的include语句。

尝试'gcc main.c -O3 -o test'导致错误,说函数f()(在sub.h中声明,在sub.c中定义,在main.c中引用)是未引用的。 尝试'gcc main.c sub.c -O3 -o test'会产生预期的行为。

然后我修改了test.c,删除了#include和对f的引用。 'gcc main.c -O3 -o test2'按预期工作。

然后我重新添加了对f的引用,忘了重新添加#include。尽管如此,'gcc main.c sub.c -O3 -o test3'按预期工作。

我注意到了这个错误,故意将include包含为'#include sub.c'。 'gcc main.c sub.c -O3 -o test4'导致错误,说f()被多次定义。 'gcc main.c -O3 -o test4按预期恢复工作。

我可以从中得出的唯一结论是,就本地文件而言,如果文件是源代码文件,则包含它并且不将其添加到命令中,否则将其源添加到命令中不要费心包括它,因为显然你是否包括它并不重要。我猜?

基本上我的问题是,是否有上述行为,如果是这样的话,那么我可以阅读它,并在将来如何处理我所包含的文件方面做出更明智的决定。

2 个答案:

答案 0 :(得分:2)

  

然后我重新添加了对f的引用,忘了重新添加#include。尽管如此,' gcc main.c sub.c -O3 -o test3'按预期工作。

对于"工作的适当宽松的定义&#34 ;;我敢打赌,f()会返回intgcc默认为C89模式。

在C99之前,如果编译器在看到函数定义或声明之前遇到函数 call ,则假定被调用函数返回int。因此,只要f()实际返回int,您的代码就会编译并成功运行。如果f() 没有返回int代码仍然会编译,但您将遇到运行时问题。所有链接器都关心的是符号在那里;它并不关心类型不匹配。

C99取消了隐式int输入,因此在C99编译器下,如果您没有在范围内f()声明,则代码将无法编译(通过包含{{ 1}}或手动添加声明)。

  

我可以从中得出的唯一结论是,就本地文件而言,如果文件是源代码文件,则包含它并且不将其添加到命令中,否则将其源添加到命令并且不要包括它,因为显然你是否包含它并不重要。我猜?

这是完全错误的结论。您希望将sub.h文件包含在另一个.c文件中作为常规练习,因为它可能会导致各种混乱。 .c中的所有内容都对main.c可见,反之亦然,从而导致潜在的命名空间冲突 - 例如,两个文件都可以定义一个" local"名为sub.c的辅助函数。通常这样的"本地"函数在源文件之外是不可见的,但是通过在另一个文件中包含一个源文件,foo()的两个版本都是可见的并且彼此冲突。另一个问题是,如果foo()文件包含另一个.c文件,其中包含另一个.c文件等,您可能会遇到一个翻译单元太大而无法使用编译器来处理。每次更改其中一个或另一个文件时,您将最终重新编译两个文件。它一直只是糟糕的做法

正确的做法是分别编译.cmain.c并确保中包含sub.c (您希望包含sub.hsub.h中确保您的声明与您的定义一致;如果不是,编译器会在翻译sub.c时牦牛。

修改

在评论中回答以下问题:

  

当你说分别编译main.c和sub.c时,我假设你的意思是分别从它们中分别制作目标文件,然后链接它们(总共3个命令)?有没有办法用一个命令来做到这一点?

命令sub.c执行相同的操作,它不会将相应的目标文件保存到磁盘。你也可以创建一个简单的Makefile,如下所示:

gcc -o test main.c sub.c

然后您需要做的就是输入CC=gcc CFLAGS=-O3 -std=c99 -pedantic -Wall -Werror SRCS=main.c sub.c OBJS=$(SRCS:.c=.o) test: $(OBJS) $(CC) -o $@ $(CFLAGS) $(OBJS) clean: rm -rf test $(OBJS)

make test

从.c文件构建目标文件有隐式规则,因此您不需要在Makefile中包含这些规则。您需要做的就是指定目标和先决条件。

您可能需要删除[fbgo448@n9dvap997]~/prototypes/simplemake: make test gcc -O3 -std=c99 -pedantic -Wall -Werror -c -o main.o main.c gcc -O3 -std=c99 -pedantic -Wall -Werror -c -o sub.o sub.c gcc -o test -O3 -std=c99 -pedantic -Wall -Werror main.o sub.o 标志以使用某些特定于平台的实用程序,并且您可能还需要指定其他标准(c89,gnu89等)。你肯定会想要保留-pedantic标志 - 他们会启用所有警告并将所有警告视为错误;他们强制你处理警告。

答案 1 :(得分:0)

如果编译程序,那么main函数应该在那里。如果编译没有main的程序,则只能生成目标文件。在您的情况下,它看起来像main.c包含main()和sub.c包含一些函数定义。其他重要的是当您定义头文件时,请确保您具有预处理器指令以防止多次包含头文件。 这里有一个例子:

http://www.tutorialspoint.com/cprogramming/c_header_files.htm