当前位置: 代码网 > 服务器>服务器>Linux > Linux下如何编译C/C++代码?从.c到.exe经历了什么?

Linux下如何编译C/C++代码?从.c到.exe经历了什么?

2024年08月06日 Linux 我要评论
Linux下如何编译C/C++代码?从.c到.exe经历了什么?会经历的四个阶段分别做了什么?

在这里插入图片描述

编译c语言指令: gcc + 文件名

如果不指定生成的 目标文件的文件名,默认生成的可执行文件的名字为 a.out

编译前:
在这里插入图片描述

编译后:
在这里插入图片描述

如何指定生成的 可执行文件的文件名呢?

方法一:
gcc + -o 选项 + 文件名1 +文件名2

方法二:
gcc +文件名2+ -o 选项 + 文件名1

解释:
文件名1:生成的可执行文件的文件名 (示例: hello.exe)
文件名2: 带编译的源文件 (示例: hello.c

指定生成的可执行文件的文件名:
在这里插入图片描述
编译c++代码:
首先如果没有安装g++命令,可以先安装一下。
安装g++命令:

yum install gcc-c++

编译指令:

g++ -o 生成的文件 待编译的文件

如果使用了c++11的语法,需要增加一个选项:
示例:

g++ -std=c++11 mycode.cc -o mycode.exe 

编译原理:
这里分享一篇不错的博客: .c到.exe的故事

四个阶段

在这里插入图片描述(图片来源于上推荐文章,图片稍作修改了)

4.1 “预处理”阶段:

前面我们是直接从.c文件到.exe可执行文件.

-e选项:让gcc开始执行程序翻译,到预处理结束后就停止。

指令: 以test.c为例。

gcc -e test.c -o test.i

-e选项表示,执行到预处理阶段完成后就停止,我们习惯将预处理后的文件用 .i文件命名,它里面依旧还是c代码,只不过更加“干净”了。

我们可以分别打开 test.ctest.i文件,查看预处理后会发生什么?

在这里插入图片描述

🔑vim使用小技巧:

可以在底行模式下,可以使用vs + 文件名 的方式,同时查看打开两个文件。
文件之间的切换: ctrl+w+w

在对预处理阶段, 会对.c文件主要完成以下工作:

  1. “头文件”展开: 也就是将所包含的头文件中的内容全拷贝过来。
  2. “条件编译”完成: 只保留满足条件的语句
  3. “宏”的替换: 宏只是简单的直接替换
  4. “注释”去掉: 注释语句时给人看的,编译器才不关心
    在这里插入图片描述

在学习c语言阶段,存在一个疑问:为什么“宏”不会做语法检查?
在这里插入图片描述
答案:
是在预处理阶段被直接替换的,而语法检查是在编译(下面讲解的)阶段进行的。在预处理阶段,已经被展开成了代码片段,而编译器只能看到这些展开后的代码片段,无法像对待普通代码一样进行语法检查。此外,可以使用一些编译器无法理解的语法,这也导致了无法进行语法检查。

注意:
因此,我们需要在编写宏时特别小心,遵循一定的规范和约定,以尽量避免出现语法错误和其他问题。在c++中,我们建议用const常量、enum、以及inline代替

补充小知识:
在这里插入图片描述

上面我们提到了gcc -e test.c -o test.i指令。

得到了下面的效果:
在这里插入图片描述

其实,我们也可以使用-d选项,gcc -e test.c -o test.i2 -dnum=2可以在使用指令的同时 定义

示例:
在这里插入图片描述
虽然在源文件test.c中并没有定义 宏num,但是预处理以后,条件编译执行以后还是打印了 num那段语句, 原因是我们使用了 -d选项。

4.2 “编译”阶段

前面我已经了解了预处理阶段的工作,那么下一步就是 “编译”了

-s选项:让gcc开始执行程序翻译,到编译结束后就停止。

在这里插入图片描述
为什么会报错呢?
在这里插入图片描述

编译阶段,我们的演示代码中, 条件编译中使用了printf函数,而在函数外的语句位置区域是不认识printf函数的,导致编译器无法识别printf函数,这就导致了报错。

那为什么预处理就直接通过了呢?
因为“语法分析”和“词法分析”是在编译阶段进行的,所以在编译阶段就直接报错了。

原“演示”代码

#include <stdio.h>
#include <math.h> 
#define pi 3.14
#ifdef pi
    printf("pi被定义了!");
#endif
#ifdef num
    printf("num被定义了!");
#endif 

int main(){
    float r=0,area=0;    //圆的半径
    printf("请输入圆的半径:");
    scanf("%f", &r);
    area = pi * r * r;   //计算圆的面积
    //printf("注释的代码");
    printf("圆的面积是 %.2f\n", area);
    return 0;
}

修改后: “演示”代码

#include <stdio.h>
#include <math.h> 
#define pi 3.14

int main(){
#ifdef pi
    printf("pi被定义了!");
#endif
#ifdef num
    printf("num被定义了!");
#endif 

    float r=0,area=0;    //圆的半径
    printf("请输入圆的半径:");
    scanf("%f", &r);
    area = pi * r * r;   //计算圆的面积
    //printf("注释的代码");
    printf("圆的面积是 %.2f\n", area);
    return 0;
}

编译阶段主要完成以下工作:

  1. 语法分析
  2. 词法分析
  3. 语义分析
  4. 符号汇总

具体是怎么完成的,牛牛就不懂了,感兴趣的小伙伴可以去查阅相关资料,编译过后,我们就形成了汇编代码。

下图示例:
在这里插入图片描述

4.3 “汇编”阶段

“编译”结束了,我们得到了汇编指令,汇编指令是计算机中的基本指令,它用于控制计算机的运行和执行各种操作。这已经算是很接近底层的语言了。

啊,好累,这么麻烦,咋还有!
在这里插入图片描述

下一个选项登场:

-c选项:让gcc开始执行程序翻译,到“汇编”结束后就停止。

注意这里是小写的c哦。

编译让我们得到汇编,那汇编就是将汇编代码翻译成 机器语言。

没错就是机器语言,也就是一串右一串二进制。

在这里插入图片描述

由于二进制文件默认情况下vim也不认识,我们可以使用xxd命令+b选项,将其重定向到mycode文件中。

xxd -b test.o>mycode

在这里插入图片描述
打开后:
在这里插入图片描述

4.4 “链接”阶段

在这里插入图片描述

总结:

在这里插入图片描述

好的,本篇博客就讲解到这里了。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com