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

孵化器网站建设长沙网站建设qq交流群

孵化器网站建设,长沙网站建设qq交流群,上海网站建站建设服务,wordpress 响应式教程文章目录0. 前言1. 程序的翻译环境和执行环境2. 被隐藏的过程2.1 翻译环境2.2 编译3.2.1 预编译3.2.2 编译2.2.3 汇编2.3 链接2.4 运行环境3. 预处理3.1 预定义符号3.2 #define3.2.1 #define定义标识符3.2.2 #define定义宏3.2.3 #define替换规则3.2.4 #和##3.2.5 带副作用的宏参… 文章目录0. 前言1. 程序的翻译环境和执行环境2. 被隐藏的过程2.1 翻译环境2.2 编译3.2.1 预编译3.2.2 编译2.2.3 汇编2.3 链接2.4 运行环境3. 预处理3.1 预定义符号3.2 #define3.2.1 #define定义标识符3.2.2 #define定义宏3.2.3 #define替换规则3.2.4 #和##3.2.5 带副作用的宏参数3.2.6 宏和函数对比3.2.7 命名约定3.3 undef3.4 命令行定义3.5 条件编译3.6 文件包含3.6.1 头文件被包含的方式3.6.2 嵌套文件包含4. 结语0. 前言 现在的我们写代码大多数用的集成开发环境IDE比如Visual Studio、Idea等这样的IDE一般都将编译和链接的过程一步完成。一句简简单单的Hello World在我们看来这一步到位小菜一碟。可是一句话说的好不是岁月静好只是有人在替你负重前行。这里面一些复杂的过程集成工具已经默默的处理掉了。可是当我们写的程序出了一些莫名其妙的错误让我们头大且掉发我们只能看到这些问题的表象难以看清本质这些问题的本质就是软件运行背后的机理及支撑软件运行的各种平台和工具如果能够了解这些机制那么对待这些问题就会有新的看法。 1. 程序的翻译环境和执行环境 在ANSI C存在两个不同的环境 翻译环境在这个环境中源代码被转换为可执行的机器指令。执行环境实际用于执行代码。 我们知道计算机只能执行二进制指令但我们一般写的代码都不是以二进制形式写以C语言为例 #includestdio.h int main() {printf(C 语言\n);return 0; }这段C语言代码如果要执行那么就需要翻译环境将其翻译为二进制指令。我们所使用的一些编译器就充当着翻译官的角色。当然了将我们的源代码转换成可执行程序这个翻译的过程能细分为2个步骤编译和链接。 2. 被隐藏的过程 2.1 翻译环境 组成一个程序的每个源文件通过编译过程转换成目标代码。 每个目标文件由链接器捆绑在一起形成一个单一而完整的可执行程序。 链接器同时也会引入标准C函数库中任何被该程序所用到的函数而且也可以搜索到我们自己写的函数将需要的函数也链接到程序中。 2.2 编译 编译可细分为三个小的过程 3.2.1 预编译 首先是源代码文件和相关的头文件被编译成一个 .i 文件。对于C程序来说它的源文件拓展名是 .c头文件拓展名是 .h 而预编译后的文件拓展名是 .i 。 预编译命令(-E表示只进行预编译) $ gcc -E test.c -o test.i 预编译过程主要处理那些源代码文件中的以 **#**开始的预编译指令。主要处理规则如下 将所有的 #define 删除并且展开所有的宏定义。处理 #include 预编译指令将被包含的文件插入到该预编译指令的位置。删除所有的注释 // 和 / ** /。添加行号和文件标识比如 #7 “test.h” 2以便于编译时编译器产生调试用的行号信息及用于产生编译错误或警告时能产生行号。报了所有的 #pragma 编译器指令因为编译器要使用他们。 经过预编译后.i 文件不包含任何宏定义因为所有的宏定义已经被展开并且包含的文件也已经被插入到 .i 。所以无法判断宏定义和头文件是否包含正确那么接下来就是通过查看编译后的文件进行判断。 3.2.2 编译 编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析、符号汇总及优化后产生相应的汇编代码文件这是这个程序构建的核心部分。 编译命令 $ gcc -S test.i 2.2.3 汇编 汇编器是将汇编代码转变成机器可以执行的指令每一个汇编语句几乎对应一条机器指令。所以汇编器的汇编过程相当于编译器来讲比较简单它没有复杂的语法也不用做优化指令只根据汇编指令和机器指令的对照表一一翻译就可以了。原来汇编才是一个血统纯正的“翻译官”啊不带任何“感情色彩”。 汇编命令 $ gcc -c test.s 汇编完成后输出目标文件、将汇编代码翻译成二进制代码存放到目标文件中同时形成符号表。 2.3 链接 现在软件开发过程中软件的规模往往都很大动辄数百万行的代码如果将这些代码全部都放在一个模块肯定无法想象。所以我们一般在写代码的时候会分模块这些模块之间相互依赖又相互独立。 那么链接就能将这些模块拼接起来最后产生一个可执行的程序。 2.4 运行环境 程序执行的过程 程序必须载入到内存中。在有操作系统的环境中这个一般由操作系统来完成。在独立的环境中程序的载入必须手工来安排也可能是通过可执行代码置入只读内存来完成。程序的执行便开始接着便调用main函数。开始执行程序代码。这时候程序将使用一个运行时堆栈存储函数的局部变量和返回地址。程序同时也可以使用静态内存存储于静态内存中的变量会一直保留。终止程序。正常终止main函数也可能意外终止程序挂掉了。 3. 预处理 3.1 预定义符号 int main() {printf(%s\n, __FILE__);//进行编译的源文件的路径printf(%d\n, __LINE__);//文件当前行号printf(%s\n, __DATE__);//文件被编译的日期printf(%s\n, __TIME__);//文件被编译的时间//VS2022不支持printf(%s\n, __STDC__);//如果编译器遵循ANSI C其值为1否则未定义return 0; }通过gcc编译器可以发现这些确实是在预编译阶段就完成了替换 3.2 #define 3.2.1 #define定义标识符 语法 #define name stuff 代码示例 #define MAX 100 #define reg register //为register关键字创建一个简短的名字 #define do_forever for(;;) //死循环 #define CASE break;case //在写case语句的时候自动把break写上。// 如果定义的stuff过长可以分成几行写除了最后一行外每行的后面都加一个反斜杠(续行符)。 #define DEBUG_PRINT printf(file:%s\tline:%d\t \date:%s\ttime:%s\n ,\__FILE__,__LINE__ , \__DATE__,__TIME__ ) 那么我们在定义 #define 的时候后面是否要加上 ; 呢 通过前面的预编译知识#define 的内容将会被替换加上 ; 会造成不必要的麻烦。 比如下面的场景 #define MAX 100; int main() {int m 0;if (m 0)m MAX;elsem -1;return 0; }我们通过gcc编译器可以看到在预编译阶段100 后面的 ;也被添加上去了导致else匹配不到if语句。 3.2.2 #define定义宏 #define 机制包括了一个规定允许把参数替换到文本中这种通常称为宏或者定义宏。 宏的声明方式 #define name( parament-list ) stuff注意 其中的partment-list是一个逗号隔开的符号表它可能出现在sturff中。参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在参数列表就会解释为stuff的一部分。 代码示例 #define SQUARE(X) X*X //求一个数的平方 int main() {printf(%d\n, SQUARE(5));printf(%lf\n, SQUARE(5.0));return 0; }但是呢这段代码还存在一定的风险如果在宏里面输入的是 (51)那么就会被替换成 5 1 * 5 1这样输出的值就和我们原本的意愿不符合。 这里我们在宏定义上加括号就能很好的解决问题。 代码示例 #define SQUARE(X) (X)*(X) //求一个数的平方 int main() {printf(%d\n, SQUARE(51));return 0; } //输出 36那这样就真的避免了风险吗当然避免了刚才出的问题但是又产生了新的问题。 代码示例 #define DOUBLE(X) (X)(X) //求一个数的平方 int main() {printf(%d\n, 10*DOUBLE(5));return 0; } //输出 55我们原意是 10 * (5 5)可是这里替换成了 10 * 5 5又违背了我们的意愿。 这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。 #define DOUBLE(X) ((X)(X)) //求一个数的平方 int main() {printf(%d\n, 10 * DOUBLE(5));return 0; } //输出 100小贴士 以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。 3.2.3 #define替换规则 在程序中扩展#define定义符号和宏时需要涉及几个步骤。 在调用宏时首先对参数进行检查看看是否包含由 #define 定义的符号。如果是它们首先被替换。替换后的文本随后被插入到程序原来的位置。对于宏参数名被他们的值所替换。最后再次对结果文件进行扫描看看是否包含由 #define 定义的符号。如果是重复上述过程。 注意 1.宏参数和 #define 定义中可以出现其他 #define 定义的符号。但是对于宏不能出现递归。 2.当预处理器搜索 #define 定义的符号的时候字符串常量的内容并不被搜索。 3.2.4 #和## 我们先来看这段代码 int main() {printf(hello world\n);printf(hello world\n);return 0; }这两句printf输出的内容其实都是一样的hello world那我们就能得出结论字符串是有自动连接特点的。 有这个结论后我们就可以这样写代码 #define PRINT(format,x) printf(the value of #x is format\n,x) int main() {int a 10;PRINT(%d, a);float b 1.5;PRINT(%f, b);return 0; }这里 # 的作用就是把一个宏参数变成对于的字符串。 ##的作用 ##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符。 注这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。 代码示例 #define CAT(x,y) x##y // RMB##100 // RMB100 int main() {int RMB100 20;printf(%d, CAT(RMB, 100));return 0; }3.2.5 带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。 例如 int main() {int a 1;int b a 1;//无副作用int c a; //有副作用return 0; }同理下面这段代码就能充分证明宏参数所引起的副作用 #define MAX(x,y) ((x)(y)?(x):(y)) int main() {//printf(%d\n, MAX(2, 3));int a 4;int b 5;int m MAX(a, b);//预处理之后//int m ((a)(b)?(a):(b));// 5 6 7printf(%d\n, m);printf(a %d b %d\n, a,b);//5 7return 0; }3.2.6 宏和函数对比 宏通常用于执行简单的运算两数中求大值。 那用函数求和这个有什么区别呢 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。更为重要的是函数的参数必须声明为特定的类型。 所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于来比较的类型。 宏是类型无关的。 当然了现在写代码时大部分还是写函数很少写宏。 宏的缺点 宏定义是插入代码中除非宏比较短否则将大幅度增大程序的长度。宏在预处理就替换了无法调试发现问题。宏与类型无关自然也就不够严谨双刃剑。宏会带来运算符优先级的问题容易导致出错。 宏和函数的一个对比 属性#define宏定义函数代码长度每次使用时宏代码都会被插入到程序中。除了非常小的宏之外程序的长度会大幅度增长函数代码只出现于一个地方每次使用这个函数时都调用那个地方的同一份代码执行速度更快存在函数的调用和返回的额外开销所以相对慢一些操作符优先级宏参数的求值是在所有周围表达式的上下文环境里除非加上括号否则邻近操作符的优先级可能会产生不可预料的后果所以建议宏在书写的时候多些括号函数参数只在函数调用的时候求值一次它的结果值传递给函数。表达式的求值结果更容易预测带有副作用的参数参数可能被替换到宏体中的多个位置所以带有副作用的参数求值可能会产生不可预料的结果函数参数只在传参的时候求值一次结果更容易控制参数类型宏的参数与类型无关只要对参数的操作是合法的它就可以使用于任何参数类型函数的参数是与类型有关的如果参数的类型不同就需要不同的函数即使他们执行的任务是相同的调试宏不方便调试函数可以逐语句调试递归宏不能递归函数可以递归 3.2.7 命名约定 一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。 那我们平时的一个习惯是 把宏名全部大写 函数名不要全部大写 3.3 undef 用于移除宏定义 #define NAME RMB #undef NAME //如果现存的一个名字需要被重新定义那么它的旧名字首先要被移除。3.4 命令行定义 许多C 的编译器提供了一种能力允许在命令行中定义符号。用于启动编译过程。 例如当我们根据同一个源文件要编译出一个程序的不同版本的时候这个特性有点用处。假定某个程序中声明了一个某个长度的数组如果机器内存有限我们需要一个很小的数组但是另外一个机器内存大些我们需要一个数组能够大些。 #include stdio.h int main() {int array [SZ];int i 0;for(i 0; i SZ; i ){array[i] i;}for(i 0; i SZ; i ){printf(%d ,array[i]);}printf(\n );return 0; }这里用gcc以命令行的形式操作可以观察到SZ通过命令行定义发生了替换。 3.5 条件编译 在编译一个程序的时候我们如果要将一条语句一组语句编译或者放弃是很方便的。因为我们有条件编译指令。 比如说 调试性的代码删除可惜保留碍事那么我们可以选择性的编译 代码示例 #define _DEBUG_ 1 int main() { #ifdef _DEBUG_printf(1\n); #endif#ifdef DEBUG //未定义所以不会编译printf(0\n); #endifreturn 0; }常见的条件编译指令 1. #if 常量表达式//... #endif //常量表达式由预处理器求值。 如 #define __DEBUG__ 1 #if __DEBUG__//.. #endif 2.多个分支的条件编译 #if 常量表达式//... #elif 常量表达式//... #else//... #endif 3.判断是否被定义 #if defined(symbol) #ifdef symbol #if !defined(symbol) #ifndef symbol3.6 文件包含 在C语言写的大大大部分的代码中我们都会用到 #include 这条指令这条指令可以使另一个文件被编译。 3.6.1 头文件被包含的方式 本地文件被包含 #include filename查找策略先在源文件所在目录下查找如果该头文件未找到编译器就像查找库函数头文件一样在标准位置查找头文件。 如果找不到就提示编译错误。 库文件包含 #include filename.h那这样来说是不是包含库文件就直接用 包含不久行了吗 理论可行但是不切实际。 3.6.2 嵌套文件包含 当项目十分庞大或者我们不小心多次包含同一个文件时 这样会造成文件的内容重复那么我们可以通过条件编译来解决这个问题。 #ifndef _TEST_H_ #define _TEST_H_ //头文件的内容 #endif //_TEST_H_这样写可能会有些麻烦写成下面这种形式就简单很多 //在VS2022中创建本地头文件编译器会自动加上 #pragma once4. 结语 本篇文章参考《程序员的自我修养——链接、装载与库》的第一章内容之后也会慢慢更新从书本中学到的知识。本周上课听老师讲计算机的一些专业名称的含义。 比如计算机科学与技术科学是摆在技术前面的扎实的理论基础更利于我们技术的提升所以在有一定技术基础的前提下可尝试学习部分理论这样会让我们的水平再往上升。
http://www.dnsts.com.cn/news/168893.html

相关文章:

  • 做网站几天能学会百度云域名注册
  • 单位网站的方案福建省交通建设质量安全监督局网站
  • 甘肃建设项目审批权限网站佛山网中互联网服务有限公司
  • 邯郸专业网站建设报价wordpress获取当前页地址
  • 云服务器做网站镜像类型选啥广州专业建网站
  • 北风淘淘网站开发公司电商网站建设方案
  • 网站开发好要租服务器吗公司网站建站哪个系统好用
  • 网站信息化建设具体内容wordpress热门文章页面
  • 医院网站建设建议知名品牌
  • 谷歌搜索引擎免费入口2022seo优化网站源码
  • 网站后台管理系统栏目位置手机版网站系统
  • 中国核工业华兴建设有限公司网站如何做网站费用多少
  • 网站营销有哪些网络优化推广公司
  • 网站开发需要什么技能泉州手机网站建设
  • 优秀设计网站大全公司邮箱从哪里登录
  • 企业网站排名提升软件智能优化网站跳转微信链接
  • 电商网站开发 参考文献呼和浩特 的网站建设
  • 专做商铺中介网站wordpress获取用户注册时间
  • 阿里云可以网站备案吗桂林两江四湖门票多少钱
  • 江门移动网站建设公司wordpress 浏览数
  • 哪些网站做的不好用新闻类网站html模板免费下载
  • 重庆建设工程监督管理局网站家装公司装修
  • 饿了吗网站有问题怎么办企业所得税政策最新2023税率
  • 已备案网站注册全球跨境电商平台排行榜前十名
  • 专业做刀具网站的公司怎么用手机做网站平台
  • 资阳住房和城乡建设厅网站深圳市建设工程服务交易中心
  • 重庆网站制作设计获客高端网站开发平台
  • 建设企业网站管理的重要性案列网站
  • 谷歌做新媒体运营的网站c 小说网站开发教程
  • 专门做书籍设计的网站网页设计怎么运行