【c语言】详解C语言预处理、编译、链接

您所在的位置:网站首页 编译与链接详解 【c语言】详解C语言预处理、编译、链接

【c语言】详解C语言预处理、编译、链接

2024-06-09 20:14| 来源: 网络整理| 查看: 265

目录

一、前言:编译器都替我做了哪些工作?

1.1 test.c   ~>  test.exe经历的步骤

1.1.1预处理

1.1.2编译

1.1.3汇编

1.1.4链接

二、正题:预处理详杂知识点

2.1#define

2.2.1#define定义标识符

2.2.2#define 定义宏

2.2.3 #define 替换规则

2.2.4趣味一题

2.3#undef

2.4条件编译

2.5文件包含

2.5.1嵌套文件包含

一、前言:编译器都替我做了哪些工作?

对于c语言的初学者来说,一上来就会对#include、 #define 这些预处理指令表示摸不着头脑,询问老师,老师便会回答 :你先不用懂,这个问题先放着吧!.......

那么今天终于到了要揭秘的时刻了!完结撒花!

1.1 test.c   ~>  test.exe经历的步骤

如图所示

编译器主要在翻译环境中帮我们完成了三个步骤:预处理、编译、汇编。

下面我们逐一讲讲 每一步具体都干了什么

1.1.1预处理

1.首先注释被替换成空格(注释被删除)

2.对头文件的包含#include进行处理 将包含的内容加入进源代码里

3.# define 重定义符号的替换

总的来说是对文本进行处理,到这一步代码还能看懂

1.1.2编译

这一步主要是把C 语言代码翻译成汇编代码

并对其进行词法分析、语法分析、语义分析、符号汇总

1.1.3汇编

将汇编代码翻译为二进制指令

生成以.o结尾的目标文件

同时生成符号表

1.1.4链接

链接目标文件和链接库生成可执行的二进制程序

合并段表

符号表的合并和重定位

ps:目前我们使用的vs2022属于集成开发环境 包含编译器和链接器。我们平时说的编译过程其实就是包括预处理、编译、汇编、链接这四个步骤。并且在一个项目中常常包含多个源文件(.c结尾的文件),他们分别经过编译器的处理生成不同的目标文件,最终在链接器的工作下一起链接成为一个最终的可执行程序!

二、正题:预处理详杂知识点 2.1#define 2.2.1#define定义标识符

语法:

#define name stuff

ps:!!!在define定义标识符的时候,不要在最后加上 ;        容易出问题

2.2.2#define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。

下面是宏的申明方式:

#define name( parament-list ) stuff

其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。

ps: 参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

逻辑比较简单用宏,计算逻辑复杂用函数!!

2.2.3 #define 替换规则

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先 被替换。

2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程。

不能出现递归!!!字符串常量中的内容并不被搜索!!!

2.2.4趣味一题

问:输出什么?

答案:一个原则纯替换 然后该咋算咋算

2.3#undef

用于移除宏定义

2.4条件编译

在一个项目中的一段调试代码有可能是跨平台的,每一段调试代码针对不同的操作系统 ,那么我们就可以使用条件编译,选择性的编译。

它可以用来解决头文件嵌套包含的问题!!

2.5文件包含

首先有两种包含方式:

1.包含本地文件(程序员自己写的.h文件) #include"xxx"

2.包含标准库的头文件                                 #include

区别:查找策略不同!!

第一种:

1.先在源文件所在目录下找2.标准库里找

第二种:

只在标准库里找

2.5.1嵌套文件包含

a.h和a.c是公共模块。

test1.h和test1.c使用了公共模块。

test2.h和test2.c使用了公共模块。

test.h和test.c使用了test1模块和test2模块。

这样最终程序中就会出现两份a.h的内容。这样就造成了文件内容的重复

解决方法:条件编译!!!

每个头文件开头这样写:

#ifndef __TEST_H__ #define __TEST_H__ //头文件的内容 #endif

 解释:

当第一次包含这个头文件 test.h 

没有定义过_TEST_H 所以判断为真,下面的代码就参与编译

若第二次包含这个头文件 test.h

#define __TEST_H__  第一次包含的时候已经定义过了 所以判断为假 下面代码不参与编译

或者

#pragma once



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3