gcc -c与gcc -o以及不加参数的区别

一、问题描述

可能你在看makefile教程的时候会碰到一个问题,就像我就碰到了,我看的是陈皓 (CSDN)前辈的教程

https://seisman.github.io/how-to-write-makefile/overview.html

我把问题贴出来,里面有一段makefile是这么写的:

edit : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
    cc -o edit main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o

这个看着有点长,为方便阐述我把这句简化一下,记作makefile(Ⅰ),主要是想要表达这个语法

edit : main.o
    gcc -o edit main.o

以前我写makefile是这么写的,记作makefile(Ⅱ):

main.o : main.c
    gcc -o main.o main.c

这个时候就犯迷糊了,啥意思啊,这咋整啊,难道以前写的makefile(Ⅱ)生成的main.o还能再改个名,改成edit不成,然后我就在shell中手动执行了一下makefile(Ⅱ)中的gcc命令,首先生成main.o:

gcc -o main.o main.c

然后再执行makefile(Ⅰ)里的写法:

gcc -o edit main.o

结果报错了:

/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

 

二、问题原因

于是搜索报错原因,说是找不到main函数的问题,莫非我把main写错了?于是去看自己的源代码,结果没有错误。那又是为啥?

翻了很多博客,最后在这篇博客里找到了原因,讲了C源文件到可执行文件的过程:

参考:https://www.cnblogs.com/qytan36/archive/2010/05/25/1743955.html

 

C源文件到可执行文件共经历了4个过程。在使用GCC编译程序时,编译过程可以被细分为四个阶段,包括预处理、编译、汇编、链接。

1、预处理

在预处理阶段,编译器主要作加载头文件、宏替换、条件编译的作用。一般处理带“#”的语句。

我们可以通过gcc 的 -E 选项进行查看,如下所示:

gcc -E main.c > main.i

编译器将main.c预处理结果输出 main.i 文件。

2、编译

在编译过程中,编译器主要作语法检查和词法分析。在确认所有指令都符合语法规则之后,将其翻译成等价的中间代码或者是汇编代码。

gcc -S main.i -o main.s

编译器将预处理结果文件main.i翻译成汇编代码main.s

3、汇编

汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码。

gcc -c main.s -o main.o

编译器将main.s文件转化为main.o 文件。

4、链接

在成功编译之后,就进入了链接阶段。链接就是将目标文件、启动代码、库文件链接成可执行文件的过程,这个文件可被加载或拷贝到存储器执行。

gcc main.o -o main.exe

编译器将main.o链接成最终可执行文件main.exe
 

三、问题解决

看了上面的博客忽然意识到,我之前在第一部分里写的命令:

gcc -o edit main.o

里面的main.o是我用命令gcc -o main.o main.c生成的可执行文件,这个main.o是我习惯性的取名为.o后缀,但我之前并不知道它是什么类型的文件。其实这个并不是通过上面第二节中第二步编译生成的.obj文件!而是最终生成的可执行的.out文件!终于知道弄错在什么地方了!

 

四、gcc -c与gcc -o以及不加参数的区别

以下摘自gcc –help的解释(gcc version 7.3.0):

-c               Compile and assemble, but do not link.
-o <file>        Place the output into <file>.
                 'none' means revert to the default behavior of guessing the language based on the file's extension.

中文翻译一下:

-c           编译和汇编,但不要链接。
-o <file>    将输出放入<文件>。
'无参数'      表示恢复为基于文件扩展名猜测语言的默认行为。

 

1、通过gcc 不加参数可以一步直接编译生成可执行文件

gcc main.c

这里生成的是可执行文件a.out,当然可以通过-o选项更改生成文件的名字,比如将生成的可执行文件命名为hello.exe

gcc main.c -o main.exe

2、gcc -c 编译生成main.o

gcc -c main.c   #生成main.o
​
gcc main.o    #不加参数,gcc自动链接上一步生成的main.o来生成最终可执行文件a.out

当然也可以通过-o选项更改生成的执行文件的名字

gcc main.o -o main.exe

好了,还有啥不懂得可以一起探讨,我也是这两天碰到修改makefile的需求才接触makefile.^^

    原文作者:忘尘~
    原文地址: https://blog.csdn.net/BobYuan888/article/details/88709449
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞