东莞建设一个网站,如何建设个人网站和博客,广东企业微信网站开发,希尔顿酒店网站建设的优点引言
众所周知#xff0c;C语言是一门高级的编程语言#xff0c;是无法被计算机直接读懂的#xff0c;C语言也不同于汇编PHP#xff0c;无法直接翻译成机器语言#xff0c;在学习的过程中#xff0c;你是否好奇过我们所敲的C语言代码#xff0c;是如何一步步翻译成机器…引言
众所周知C语言是一门高级的编程语言是无法被计算机直接读懂的C语言也不同于汇编PHP无法直接翻译成机器语言在学习的过程中你是否好奇过我们所敲的C语言代码是如何一步步翻译成机器语言的呢今天这篇博客---编译和链接就是要带领我们解决这样的问题那么我们开始吧
翻译环境和执行环境
在ANSI C的任何一种实现中存在两个不同的环境 1.翻译环境在这个环境中源代码被转化为可执行的机器指令二进制指令 2.执行环境用于执行代码 1.翻译环境
在翻译环境中分为编译和链接两部分 我们电脑中的编译器在将我们的代码文件编译后生成一个.obj文件注在Linux中会生成.o文件这个.obj文件就是一份机器可以读懂的01010101文件二进制文件 。通过连接器作用最终将多份.obj文件链接生成一份可执行程序.exe文件。.obj文件和链接库链接库是指运⾏时库(它是⽀持程序运行的基本函数集合)或者第三方库。
编译分为预编译预处理编译和汇编三部分 在编译环境中的预编译预处理过程中主要做这些工作 将所有的#define 删除并展开所有的宏定义 处理所有的条件编译指令如 #if、#ifdef、#elif、#else、#endif 处理#include预编译指令将包含的头⽂件的内容插⼊到该预编译指令的位置。这个过程是递归进行的也就是说被包含的头⽂件也可能包含其他⽂件删除所有的注释添加⾏号和⽂件名标识⽅便后续编译器⽣成调试信息等保留所有的#pragma的编译器指令编译器后续会使⽤ 在编译环境的编译过程中其本质是把代码翻译成汇编代码主要执行三步 1.词法分析 2.语法分析 3.语义分析 最后汇编是将汇编代码转成机器语言代码二进制指令 编译环境的第二部分链接就是把一堆目标文件链接在一起生成可执行程序.exe
关于编译链接更细节的内容大家可以参考《编译原理》和《程序员的自我修养》这两本书
2.运行环境 1.程序载入内存中。 2.程序开始执行。调用main 3.开始执行代码。这个时候将使用一个函数栈帧存储函数的局部变量和返回地址 4.终止程序。正常/意外终止 到了这里编译和链接的大致过程已经讲完了但是关于编译中预处理还有很多需要知道的细节需要单独拿出来细讲所以想更多了解的朋友可以继续看下去。
预处理详解
1.预定义符号
在C语言中设置了一些比较方便的预定义符号可以直接使用预定义符号也是在预处理期间处理的 1.__FILE__ //进行编译的源文件 2.__LINE__ //文件当前的行号 3.__DATE__ //文件被编译的日期 4.__TIME__ //文件被编译的时间 5.__STDC__ //如果编译器遵循ANSI C其值为1否则未定义 下面代码来带大家简单使用一下
#includestdio.h
int main()
{printf(%s\n%d\n%s\n%s, __FILE__, __LINE__, __DATE__, __TIME__);return 0;
} 根据上方的代码运行大家应该基本就能弄清这些 预定义符号的作用了
2.#define定义的常量
基本语法 #define name stuff //以下是实际运用
#define MAX 1000
#define MIN 100;//不要在#define定义的常量后加分号//介于其预处理暴力替换的特性会导致一些错误//如以下代码就会出错
printf(%d,MIN);//此代码预处理过后为-printf(%d,100;);
if(condition)max MIN;// 此处预处理过后为两条语句会将if和else隔开出现报错
elsemax 0;
3.#define定义宏 #define机制包括了一个规定允许把参数替换到文本中这种实现被称为宏macro或定义宏define marco。
下面是宏的声明方式 #define name( parament-list ) stuff 其中的parament-list是一个由逗号隔开的符号表它们可能出现在stuff中。
注参数列表的左括号必须与name紧邻如果两者之间有空白存在参数列表就会被解释成stuff的一部分。 使用举例 #define SQUAREx x * x 这个宏接受一个参数x如果在上述声明之后将SQUSRE5放到程序中预处理器就会将此语句替换成5 * 5
警告
#define定义的宏是一种暴力的替换实在预处理过程中将语句原样替换如果你写了如下代码
#includestdio.h
#define SQUARE(x) x*x
int main()
{int a 5;printf(%d\n, SQUARE(5 1));return 0;
}将会打印什么呢 也许你会觉得会打印366*6但是 结果可能与预期不符暴力替换此语句便成为 5 1 * 5 1而不是5 1*5 1 所以最后的结果是11
如果想要36这种结果应该怎么办呢那就不要吝啬你的了这样写 #define SQUARE(x) ((x)*(x)) 最后代码替换为 51*51就为36了
所以在用#define定义宏的时候把括号都带上可以尽量避免在使用宏时由于参数中的操作符或临近操作符之间不可预料的相互作用
4.带有副作用的宏参数
当宏参数在宏定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
例如 x1; //不带有副作用 x; //带有副作用 MAX宏可以证明具有副作用的参数所引起的问题
#includestdio.h
#define MAX(x,y) ((x)(y)?(x):(y))
int main()
{int a 5;int b 8;int c MAX(a, b);printf(%d\n%d\n%d\n, a, b, c);return 0;
}
根据暴力替换我们知道预处理之后的结果为 c ( (a) (b) ? (a) : (b)); 所以最后的输出结果为a6,b10,z9 5.宏替换规则
在程序中扩展#define定义符号和宏时需要涉及几个步骤。
1.在调用宏时首先参数进行检查看看是否包含任何由#define定义的符号。如果有首先被替换
2.替换文本随后被插入到程序中原来文本的位置。对于宏参数名被其值所替换
3.最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号。如果是就重复上述处理过程。 注意 1.宏参数和#define定义中可以出现其他#define定义的符号。但对于宏不能出现递归 2.当预处理搜索#define定义符号的时候字符串常量的内容不被搜索 6.宏和函数的对比
宏通常被应用于执行简单的运算。
但运用函数执行比较简单的运算如比大小时会有两点缺点 1.⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐ 函数在程序的规模和速度⽅⾯更胜⼀筹。 2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之 这个宏怎可以适⽤于整形、⻓整型、浮点型等可以⽤于 来⽐较的类型。宏是类型⽆关的。 但和函数相比时宏也有其劣势 1.每次使⽤宏的时候⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短否则可能⼤幅度增加程序 的⻓度。 2. 宏是没法调试的。 3. 宏由于类型⽆关也就不够严谨。 4. 宏可能会带来运算符优先级的问题导致程容易出现错。 7.#和##
1.#运算符
#运算符将宏的一个参数转换为字符串字面量且只允许出现在带参数的宏的替换列表中。
#运算符所执行的操作可以理解为“字符串化”。
如果我们有一个变量int a 10想打印出the value of a is 10.
就可以写 #define PRINTn printf(the value of #nis %d,n) 当我们用以上方式调用的时候
PRINTa//中#a就转换成了a
可以看看下方代码及运行
#includestdio.h
#define PRINT(n) printf(the value of #n is %d\n,n)
int main()
{int a 10;PRINT(a);return 0;
} 2.##运算符
##可以把位于它两边的符号合成一个符号它允许宏定义从分离的文本片段创建标识符。##被称为记号粘合
注这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
这里来举个例子如果我们想写一个函数用来求两个数中较大的那个不同的类型就需要写不同的函数像下面这样
int int_max(int x, int y)
{return x y ? x : y;
}float float_max(float x, float y)
{return x y ? x : y;
}
但是基本类型很多给每一个类型的比较都写一个函数未免太繁琐了我们现在了解了##便可以这样写
#includestdio.h
#define GENERIC(type) \
type type##_max(type x,type y) \
{ \return xy?x:y; \
}
//这里解释一下\符号是连行符用这个符号可以将本行和下一行连接相当于一行
GENERIC(int);
GENERIC(float);//想生成什么类型的直接在这声明一下就行
int main()
{float a 10.9, b 20.5;printf(%f\n, float_max(a, b));int m 10, n 20;printf(%d\n, int_max(m, n));return 0;
} 8.#undef 这条指令可以用于移除一个宏定义 #undef NAME //如果现存的一个名字需要被重定义它的旧名字首先要被移除 9.条件编译
在编译一个程序的时候我们如果想要将一条或一段语句编译或者放弃编译可以使用条件编译指令。
比如一段调试代码删除比较可惜保留又碍事可以使用选择性的编译见代码
#includestdio.h
#define __DEBUG__
int main()
{int arr[10] { 0 };for (int i 0; i 10; i) {arr[i] i;
#ifdef __DEBUG__printf(%d , arr[i]);
#endif}return 0;
} 当你把开头#define去掉时接下来将什么都不会打印了 下面还有一些比较常见的条件编译指令
1.
#if 常量表达式//。。。
#endif2.多个分支的条件编译
#if 常量表达式//。。。
#elif 常量表达式//。。。
#else 常量表达式//。。。
#endif3.判断是否被定义
#if defined(sympol)
#ifdef sympol
//上方两语句意思相同
#if !defined(sympol)
#ifndef sympol
//上方两语句意思相同4.嵌套指令
没什么说的这些指令可以相互嵌套使用
10.头文件的包含 1.本地头文件包含 #include filename 查找规则 现在源文件所在目录下查找如果该头文件未找到编译器就像查找库函数头文件一样在标准位置查找头文件。 如果找不到则编译错误。 2.库文件包含 #include filename.h 查找规则 查找头文件直接去标准路径下去查找如果找不到就提示编译错误。 这种查找规则其实意味着库函数的头文件其实也可以用 的形式包含但是考虑到对头文件的区分管理和效率依然建议用 的形式去包含库文件。
11.头文件被反复包含问题
当你在coding的时候是否会有时候将同一个头文件反复包含像下面这样
//test.c文件
#includetest.h
#includetest.h
#includetest.h
#includetest.h
#includetest.h
int main()
{return 0;
}如果直接这样写test.c文件中将test.h包含五次那么test.h文件的内容将会被拷贝5份在test.c中
如果test.h比较大这样会使预处理的代码量加剧会极大的影响到程序运行的效率那么应该如何解决这种问题呢
答案是条件编译
//test.h头文件
#ifndef __TEST_H__
#define __TEST_H__
//头文件内容
#enif //__TEST_H__
或者 #pragma once 看看你是否在生成头文件是看到过这句代码这句代码的意义便是防止头文件被反复包含这种问题的。
12.其他预处理指令 #error #pragma #line #pragma pack//结构体中介绍过用来设置默认对齐数 //。。。 等等一系列预处理指令这里就不一一赘述了 如果对相关内容有兴趣可以参考《C语言深度解剖》
结语
到这里关于编译链接以及对预处理的内容基本上是介绍的差不多了如果感觉我的博客有帮助的话还请点个小小的赞支持一下哦我还会继续产出更多有趣的内容。比心---♥ 文章转载自: http://www.morning.hcwjls.com.gov.cn.hcwjls.com http://www.morning.hfytgp.cn.gov.cn.hfytgp.cn http://www.morning.nydgg.cn.gov.cn.nydgg.cn http://www.morning.hous-e.com.gov.cn.hous-e.com http://www.morning.twfdm.cn.gov.cn.twfdm.cn http://www.morning.yhsrp.cn.gov.cn.yhsrp.cn http://www.morning.mzcsp.cn.gov.cn.mzcsp.cn http://www.morning.gynls.cn.gov.cn.gynls.cn http://www.morning.xwnnp.cn.gov.cn.xwnnp.cn http://www.morning.rydhq.cn.gov.cn.rydhq.cn http://www.morning.dgfpp.cn.gov.cn.dgfpp.cn http://www.morning.nxzsd.cn.gov.cn.nxzsd.cn http://www.morning.fllfc.cn.gov.cn.fllfc.cn http://www.morning.rwzqn.cn.gov.cn.rwzqn.cn http://www.morning.klrpm.cn.gov.cn.klrpm.cn http://www.morning.drndl.cn.gov.cn.drndl.cn http://www.morning.tllws.cn.gov.cn.tllws.cn http://www.morning.xqmd.cn.gov.cn.xqmd.cn http://www.morning.lzdbb.cn.gov.cn.lzdbb.cn http://www.morning.pwgzh.cn.gov.cn.pwgzh.cn http://www.morning.wwxg.cn.gov.cn.wwxg.cn http://www.morning.plqqp.cn.gov.cn.plqqp.cn http://www.morning.xflzm.cn.gov.cn.xflzm.cn http://www.morning.kscwt.cn.gov.cn.kscwt.cn http://www.morning.zbqry.cn.gov.cn.zbqry.cn http://www.morning.rlxg.cn.gov.cn.rlxg.cn http://www.morning.haibuli.com.gov.cn.haibuli.com http://www.morning.gthwr.cn.gov.cn.gthwr.cn http://www.morning.whpsl.cn.gov.cn.whpsl.cn http://www.morning.wrfk.cn.gov.cn.wrfk.cn http://www.morning.lthpr.cn.gov.cn.lthpr.cn http://www.morning.kjgrg.cn.gov.cn.kjgrg.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.gqfbh.cn.gov.cn.gqfbh.cn http://www.morning.dbsch.cn.gov.cn.dbsch.cn http://www.morning.mprpx.cn.gov.cn.mprpx.cn http://www.morning.hkshy.cn.gov.cn.hkshy.cn http://www.morning.iterlog.com.gov.cn.iterlog.com http://www.morning.tqsmc.cn.gov.cn.tqsmc.cn http://www.morning.mqss.cn.gov.cn.mqss.cn http://www.morning.gzgwn.cn.gov.cn.gzgwn.cn http://www.morning.yccnj.cn.gov.cn.yccnj.cn http://www.morning.zzbwjy.cn.gov.cn.zzbwjy.cn http://www.morning.fktlr.cn.gov.cn.fktlr.cn http://www.morning.sdkaiyu.com.gov.cn.sdkaiyu.com http://www.morning.pypbz.cn.gov.cn.pypbz.cn http://www.morning.dyxlj.cn.gov.cn.dyxlj.cn http://www.morning.whnps.cn.gov.cn.whnps.cn http://www.morning.mkydt.cn.gov.cn.mkydt.cn http://www.morning.lmtbl.cn.gov.cn.lmtbl.cn http://www.morning.skkmz.cn.gov.cn.skkmz.cn http://www.morning.lkkgq.cn.gov.cn.lkkgq.cn http://www.morning.ljllt.cn.gov.cn.ljllt.cn http://www.morning.fdrwk.cn.gov.cn.fdrwk.cn http://www.morning.bnkcl.cn.gov.cn.bnkcl.cn http://www.morning.nmtyx.cn.gov.cn.nmtyx.cn http://www.morning.nzmhk.cn.gov.cn.nzmhk.cn http://www.morning.mhrzd.cn.gov.cn.mhrzd.cn http://www.morning.lzqtn.cn.gov.cn.lzqtn.cn http://www.morning.nkjpl.cn.gov.cn.nkjpl.cn http://www.morning.ppgdp.cn.gov.cn.ppgdp.cn http://www.morning.rfpq.cn.gov.cn.rfpq.cn http://www.morning.lnnc.cn.gov.cn.lnnc.cn http://www.morning.kcxtz.cn.gov.cn.kcxtz.cn http://www.morning.wknbc.cn.gov.cn.wknbc.cn http://www.morning.pkrb.cn.gov.cn.pkrb.cn http://www.morning.kjgdm.cn.gov.cn.kjgdm.cn http://www.morning.xgzwj.cn.gov.cn.xgzwj.cn http://www.morning.twfdm.cn.gov.cn.twfdm.cn http://www.morning.bgxgq.cn.gov.cn.bgxgq.cn http://www.morning.nlzpj.cn.gov.cn.nlzpj.cn http://www.morning.nmlpp.cn.gov.cn.nmlpp.cn http://www.morning.ywzqk.cn.gov.cn.ywzqk.cn http://www.morning.kdjtt.cn.gov.cn.kdjtt.cn http://www.morning.gyxwh.cn.gov.cn.gyxwh.cn http://www.morning.dtzxf.cn.gov.cn.dtzxf.cn http://www.morning.fwwkr.cn.gov.cn.fwwkr.cn http://www.morning.plydc.cn.gov.cn.plydc.cn http://www.morning.knlbg.cn.gov.cn.knlbg.cn http://www.morning.lsssx.cn.gov.cn.lsssx.cn