浅显易懂的GCC使用教程 您所在的位置:网站首页 编译o3 浅显易懂的GCC使用教程

浅显易懂的GCC使用教程

2023-09-27 16:10| 来源: 网络整理| 查看: 265

【指令】 gcc   使用gcc指令编译*.c文件可以生成*exe可执行文件。下面我们用一段简单的c代码来讲解,Demo.c内源码如下:

#include int main(void) { printf("nihao\n"); return 0; }

  打开cmd,需要注意的是cmd默认路径一般是c盘,而Demo.c文件可能并不在cmd的默认路径下,我们需要使用dos指令cd到Demo.c所在目录下才能对文件进行操作,示例:

alt test

  对Demo.c文件执行gcc指令后会在该目录下生成可执行文件a.exe,由于没有制定exe的文件名所以默认为a.exe。

alt text

  当然也不一定要cd进Demo.c的目录,使用gcc指令时给出Demo.c的绝对路径也可以成功编译,命令如下:

gcc E:\WorkSpace\Test_gcc\Demo.c

【指令】 -o   指令-o(小写)用来指定生成的文件名。

alt text

结果如下:

alt text

  生成的文件不一定要在.c所在目录,可以给出路径指定。

gcc Demo.c -o ..\Demo.exe

  该指令指定将exe生成到上一级目录。

  生成exe后我们试者执行一下看看结果。

alt text

【指令】 -E(预处理(Preprocessing))   指令 -E(大写)将执行预处理操作也即生成*.i文件,gcc编译器将对#开头的指令进行解析。我们修改Demo.c中的代码为如下:

#include #include #include "Test.h" int main() { int a = N; //宏常量 int b = 2; int c = 0; c = a + b; printf("%d\n", c); CODE //宏替换代码段 DoNothing(); system("pause"); return 0; }

在Demo.c同目录下编辑Test.h文件,源码如下:

#define N 1 #define CODE if(c > 2) \ { \ printf("c > 2\n"); \ } void DoNothing(void); //函数声明(该函数未被调用)

在Demo.c同目录下编辑Test.c文件,源码如下:

#include"Test.h" void DoNothing(void) { ; return ; }

  从源码可知Demo.c中在预处理阶段需要把调用的头文件包含进来,替换宏常量和宏代码段。我们执行指令gcc -E Demo.c -o Demo.i并看看Demo.i文件中的代码。

Demo.i文件内容:

alt text

  -E 指令使gcc执行预处理,预处理时对#类指令进行处理(包含头文件、替换宏常量和宏代码段等操作),也就不难理解为何Demo.i文件会很大了(38KB),整个工程最后被揉合成一个大文件。预处理把注释都去掉了,所以反编译回来的代码是没有注释的!因为注释早就被去掉了。另外可以一提的是使用指令gcc -E Demo.c不指定输出的文件名时内容将会直接输出到Dos框中,而不会产生文件。

  我们知道c语言出现语法错误时编译器将会报错,但检查语法错误是在预处理、编译、汇编、链接、生成可执行文件中的哪个阶段执行的呢?为了方便我们编辑Demo2.c代码,有意使源码代码由于错误测试预处理阶段是否会报语法错误。

#include int main(void) { aabbccdd //此处有语法错误 return 0; }

  对Demo2.c执行预处理操作gcc -E Demo2.c。

alt test

  由此可知预处理阶段不检查语法错误。

【指令】 -S(编译(Compiling))   执行-S(大写)指令将*.i文件中源码转化为汇编代码*.s文件。我们执行指令gcc -S Demo.i -o Demo.s,在当前目录下将生成Demo.s文件,用记事本打开会发现c源码已经被编译器转化为汇编代码。

在这里插入图片描述

  如果使用指令gcc -S Demo.i即不指定输出文件名,默认也将会在当前目录下产生文件Demo.s。

  关于前面含有语法错误的Demo2.c我们在编译阶段再试一次,看看是否能检查出语法错误。

alt text

  对语法的检查是再编译阶段进行的。

【指令】 -c(汇编(Assembling))   执行-c(小写)指令将*.s文件中的汇编源码转化未机器能执行的二进制机器码,生成文件*.o。执行指令gcc -c Demo.s -o Demo.o。生成的Demo.o为二进制文件,用记事本打开就是一堆乱码,我这里就不贴图出来了。

【指令】 gcc *.o(链接(Linking))   经过汇编处理后生成的二进制文件Demo.o虽然已经机器码,但仍然无法运行因为少了链接操作。链接操作可执行指令gcc Demo.o -o Demo.exe

alt text

  对Demo.o执行链接操作出现报错,提示找不到函数DoNothing的定义。预处理阶段值时将头文件包含进Demo.i文件中,也即Demo.i中含有函数的声明部分,所以编译阶段只检查函数的声明和调用处是否符合函数原型,并未去检查其他*.c文件中的函数定义。   链接阶段就是要把函数库中的函数定义给关联进来,找不到函数定义当然会报错。那么问题来了,我们调用的标准库函数printf为何不报错?其实库函数也不例外,在链接阶段需要关联到函数定义,它的声明部分在标准库函数头文件stdio.h中已给出,而实现部分在某个标准库中封装好了,不同的系统下还会有差异。gcc在链接时默认是包含标准库的库文件路径的,所以它能找到printf函数的定义而不会报错。而DoNothing函数是我们用户自己编写,并未封装成库的形式gcc当然找不到它的定义。倘若把Demo.c中的DoNothing函数调用去掉可以成功执行链接操作吗?当然可以!

  为了让Demo.o能成功的生成可执行文件Demo.exe,我们可以将Test.c封装成静态库供其调用,这样就有函数定义了。执行指令gcc -c Test.c -o Test.o生成Test.o二进制文件。这里并不是不用对Test.c执行预处理和编译操作,而是编译器帮我们做了。接着将Test.o生成静态库文件libTest.a,然后再次尝试对Demo.o执行链接操作。

alt text

  可以看到这次编译器没有报错且成功生成了Demo.exe,执行结果也与预期一直。   关于生成静态库和动态库的gcc指令以及更多其他指令,静态库和动态库的区别和作用,等有时间了继续写个中级篇来讲解吧,一篇文章写得太长大家看了也会枯燥,我写着也需要休息。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有