当前位置: 首页 > news >正文

c语言编译和链接

一个.c源文件是如何经过处理变成可执行的.exe文件?

这其中经过了编译和链接两个大过程。总的来讲,就是每个源文件经过编译后生成对应地目标文件,然后所有的目标文件和所引用的标准库链接,形成了.exe文件。具体是怎样,我来讲一讲。

1.编译

a.预处理

此时.c文件进入预处理阶段,执行预处理命令。比如#define,#undef,(#ifdef,#endif),#error,#line等等。预处理结束后,将生成.i文件。

b.编译

此时.i文件进入编译阶段,此时编译器对.i文件进行语法分析,词法分析,语义分析,符号汇总,其实就是把c语言指令翻译成汇编指令,那么前三个就很好理解了,符号汇总是干什么呢?符号汇总是把文件中出现的一些函数名等一些特殊的名字记录下来,比如main。之后就生成一个.s文件。

c.汇编

此时.s文件进入汇编阶段,编译器将.s文件中的汇编指令翻译成二进制指令,生成.o文件。在这一阶段,将生成符号表,符号中的符号就是编译阶段中记下的特殊的名字,而表就是把这些名字和它的地址关联起来作出一个表。比如写了一个add函数,那么将add和add的地址联系起来,但是如果在这单独的.c文件中,只有add的声明,而没有定义,则将其地址记为0.

2.链接

链接很重要的一个地方就是合并符号表,在之前讲到,如果在这单独的.c文件中,只有add的声明,而没有定义,则将其地址记为0。而在另一个.c文件内发现了add的定义,则将add函数定义的地址替换掉这个0。然后将标准库中函数的地址也进行相同操作。

最后呢,就生成了可执行的.exe文件。

然后有几个需要注意的点

1.#include "stdio.h" 和 #include <stdio.h> 的区别

""的操作是先到本地文件中寻找,然后到标准库中寻找,而<>则是直接到标准库中寻找。所以对于本地的.h文件,使用 "" ,标准库应使用 <> 。

2.宏和函数的区别

a.宏比函数更快,宏只是一个寻找替换的过程,而调用函数,要现在栈区内开辟空间,然后开辟形参等一系列操作,所以对于简单的逻辑,宏更好。

b.宏没有参数限制,宏只是寻找替换,所以根本就不会检查参数。如下面这个宏。

#define MALLOC(num, type) (type*)malloc(num * sizeof(type))int main()
{int* x = MALLOC(10, int);if (x == NULL){//------return 0;}int i = 0;for (i = 0; i < 10; i++)x[i] = i;for (i = 0; i < 10; i++)printf("%d ", x[i]);return 0;
}

函数肯定写不出来这种效果,应该函数的参数是有类型限制的,没有一种参数它的类型是类型。

但是这样也说明,函数比宏更为严谨。

c.宏可能会有副作用

因为宏只是寻找替换,对于这样一个宏。

#define x(a, b) ((a > b)?(a):(b))

如果传入的a和b分别为a++,b++,这很有可能把某个++执行了两边。 

d.宏不能调试,不能递归,而函数可以。

e.因为宏是寻找替换,所以每使用一个宏就会替换一次,这可能大大增加了代码量,而函数则不会。

3.  5个预编译符号

__FILE__//进行编译的源文件

__LINE__//文件当前的行号

__DATE__//文件被编译的日期

__TIME__//文件被编译的时间

__STDC__//如果编译器遵循ANSI C,其值为1,否则未定义

int main()
{printf("%s\n %s\n %s\n %d\n",__FILE__,__DATE__,__TIME__,__LINE__);return 0;
}

          

相关文章:

  • 二分图
  • web CSS笔记1
  • lua 获取指定路径下的所有文件夹
  • 批量删除 rabbitmq中随机队列
  • c++部分题
  • PCL点云处理之最小中值平方(Lmeds法)拟合平面(二百三十四)
  • 鸿蒙OS开发实例:【手撸服务卡片】
  • 【Linux】详解进程程序替换
  • 基于前端技术实现的全面预算编制系统
  • 利用RWKV-Runner初步感受一下ai的世界
  • Linux的学习之路:3、基础指令(2)
  • SpringBoot集成WebSocket(实时消息推送)
  • PL/SQL的词法单元
  • ida调试技巧-通过修改zf寄存器的值绕过简单反调试
  • Linux manim安装
  • JavaScript HTML DOM
  • Javascript弹出层-初探
  • Java面向对象及其三大特征
  • Linux gpio口使用方法
  • Next.js之基础概念(二)
  • PHP的Ev教程三(Periodic watcher)
  • Quartz初级教程
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • socket.io+express实现聊天室的思考(三)
  • vue.js框架原理浅析
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 基于Android乐音识别(2)
  • 思维导图—你不知道的JavaScript中卷
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 问题之ssh中Host key verification failed的解决
  • 小李飞刀:SQL题目刷起来!
  • 一份游戏开发学习路线
  • 阿里云重庆大学大数据训练营落地分享
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # 安徽锐锋科技IDMS系统简介
  • #1015 : KMP算法
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (2)MFC+openGL单文档框架glFrame
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (定时器/计数器)中断系统(详解与使用)
  • (二)Eureka服务搭建,服务注册,服务发现
  • (二)hibernate配置管理
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .aanva
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .netcore如何运行环境安装到Linux服务器
  • @Autowired自动装配
  • @RequestBody的使用
  • [BZOJ4010]菜肴制作