C/C++之从源文件到可执行程序

搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88537509

学习了一下makefile的写法,跟我一起写 Makefile(一),顺便看看源文件是怎么变成可执行程序的。
GCC干了些什么事情呢?在CSAPP的1.2节中讲得很清楚了:


gcc有四个阶段:预处理——编译——汇编——链接。于是在makefile中可以明显地看到最终的可执行目标程序依赖于一堆.o文件(可重定位目标程序),这一堆.o文件是由链接器ld来进行组合打包的,而.o文件又依赖于对应的.c文件(源文件)。
所以,假如有多个源文件,例如有main函数在hello.c中,在main函数中又分别调用了位于msg1.c和msg2.c中的msg1函数和msg2函数,那么gcc在编译hello.c的过程中其实是“不涉及”msg1.c和msg2.c文件的,要用gcc hello.c msg1.c msg2.c -o hello这样的命令分别生成三个源文件对应的.o文件,再由链接器把.o文件们打包组合成hello这个可执行程序。
那么就有个地方要注意了:在C语言中,函数在调用前不一定非要声明。如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码。
会产生什么样的问题呢?参考万恶之源:C语言中的隐式函数声明,当隐式声明函数名称恰好在链接库中存在,但返回非int类型时,就会导致错误。所以呢,强烈建议程序员重视编译器给出的关于隐式声明的警告,及时通过包含必要的头文件来消除这种警告

来看看实例吧:

1 //hello.c
2 #include <stdio.h>
3 int main()
4 {
5     printf("Hello, world!\n");
6     msg1();
7     msg2();
8     return 0;
9 }
1 //msg1.c
2 #include <stdio.h>
3 void msg1(void)
4 {
5     printf("the message sent from msg1\n");
6 }
1 //msg2.c
2 #include <stdio.h>
3 void msg1(void)
4 {
5     printf("the message sent from msg2\n");
6 }

在hello.c中没有声明msg1和msg2这两个函数,用gcc hello.c msg1.c msg2.c -o hello命令得到这样的警告:

hello.c: In function ‘main’:
hello.c:5:3: warning: implicit declaration of function ‘msg1’ [-Wimplicit-function-declaration]
   msg1();
   ^
hello.c:6:3: warning: implicit declaration of function ‘msg2’ [-Wimplicit-function-declaration]
   msg2();
   ^

但是仍然生成了hello可执行文件,执行一下,输出正常:

Hello, world!
the message sent from msg1
the message sent from msg2

那么假如在编译的时候没有加入msg2.c会提示什么呢?gcc hello.c msg1.c -o hello看看,除了之前的警告信息外,还有error: ld returned 1 exit status,链接器ld找不到要依赖的文件了。

hello.c: In function ‘main’:
hello.c:5:3: warning: implicit declaration of function ‘msg1’ [-Wimplicit-function-declaration]
   msg1();
   ^
hello.c:6:3: warning: implicit declaration of function ‘msg2’ [-Wimplicit-function-declaration]
   msg2();
   ^
/tmp/ccYSfgV0.o: In function `main':
hello.c:(.text+0x27): undefined reference to `msg2'
collect2: error: ld returned 1 exit status

上面提到的隐式函数声明,在C++中是没有的,对未声明的函数进行调用会无法通过编译,把gcc改为g++再来试试,g++ hello.c msg1.c msg2.c -o hello,果然error了:

hello.c: In function ‘int main()’:
hello.c:5:8: error: ‘msg1’ was not declared in this scope
   msg1();
        ^
hello.c:6:8: error: ‘msg2’ was not declared in this scope
   msg2();
        ^

对了,关于头文件和源文件的关系还有一篇文章可以参考:.c和.h文件的区别

猜你喜欢

转载自www.cnblogs.com/lyrich/p/10552471.html