96SEO 2026-02-23 14:35 10
第1种是翻译环境在这个环境中源代码经过编译和链接被转换为可执行的机器指令。

第2种是执行环境它用于实际执行代码。
因为我们所书写的代码都是文本信息计算机只能识别二进制计算机不能直接理解文本信息就需要将文本信息转为二级制指令然后再去执行这些指令。
组成一个程序的每个源文件通过编译过程分别转换成目标代码object
每个目标文件由链接器linker捆绑在一起形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数而且它可以搜索程序员个人的程序库将其需要的函数也链接到程序中。
注由于vs已经将编译和链接集成开发环境不方便看到这些过程咱们在gcc编译器测试。
预处理Preprocessing预处理器Preprocessor根据程序中包含的预编译指令如#include等将源代码中的宏定义、注释、条件编译等转换为实际的C代码。
预处理的输出结果通常是一个扩展名为.i的文件。
编译Compilation编译器Compiler将扩展名为.i的预处理后的文件编译成汇编语言Assembly
Language代码这个汇编代码是计算机可以理解的中间语言。
编译的输出结果通常是一个扩展名为.s的汇编语言代码文件。
汇编Assembly汇编器Assembler将扩展名为.s的汇编语言代码文件转换成计算机可执行的机器码Machine
链接Linking链接器Linker将程序中使用到的各个目标文件和库文件Library链接成一个完整的可执行文件Executable
File。
器链接的输出结果通常是扩展名为.exe的可执行文件。
预处理完成之后就停下来预处理之后产生的结果都放在test.i文件中。
链接之后就停下来结果保存在test.o中。
test.ot和test.exe都是按照
这种文件的格式来存储的可通过Linux下的readelf阅读该文件例如readelf
程序必须载入内存中。
在有操作系统的环境中一般这个由操作系统完成。
在独立的环境中程序的载入必须由手工安排也可能是通过可执行代码置入只读内存来完成。
程序的执行便开始。
接着便调用main函数。
开始执行程序代码。
这个时候程序将使用一个运行时堆栈stack存储函数的局部变量和返回地址。
程序同时也可以使用静态static内存存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
终止程序。
正常终止main函数也有可能是意外终止。
:;//最后一个case语句的分号//最后一个case语句可以不用写break}return
机制包括了一个规定允许把参数替换到文本中这种实现通常称为宏macro或定义宏define
如果两者之间有任何空白存在参数列表就会被解释为stuff的一部分。
{printf(%d\n,SQUARE(5));//替换为SQUARE(5)
这样就比较清晰了由替换产生的表达式并没有按照预想的次序进行求值。
在宏定义上加上两个括号这个问题便轻松的解决了
总结所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号。
如果是它们首先被替换。
替换文本随后被插入到程序中原来文本的位置。
对于宏参数名被他们的值所替换。
最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号。
如果是就重复上述处理过程。
定义中可以出现其他#define定义的符号。
但是对于宏不能出现递归。
当预处理器搜索#define定义的符号的时候字符串常量的内容并不被搜索会把宏当作字符串的内容处理。
我们发现上面的代码除了变量和变量的值不同之外输出模式都是一样那我们是否可以将打印封装成一个函数呢
我们发现函数无法实现那宏呢如何把参数插入到字符串中如何传入的类型为浮点型呢
注意这样的连接必须产生一个合法的标识符。
否则其结果就是未定义的。
当宏参数在宏的定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。
副作用就是表达式求值的时候出现的永久性效果。
用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多,调用函数会形成栈帧和释放栈帧。
所以宏比函数在程序的规模和速度方面更胜一筹。
更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。
反之这个宏可以适用于整形、长整型、浮点型等可以
宏有时候可以做函数做不到的事情。
比如宏的参数可以出现数据类型但是函数做不到。
每次使用宏的时候一份宏定义的代码将插入到程序中。
除非宏比较短否则可能大幅度增加程序的长度。
宏是没法调试的。
宏由于类型无关也就不够严谨。
宏可能会带来运算符优先级的问题导致程容易出现错。
度每次使用时宏代码都会被插入到程序中。
除了非常小的宏之外程序的长度会大幅度增长函数代码只出现于一个地方每次使用这个函数时都调用那个
除非加上括号否则邻近操作符的优先级可能会产生不可预料的后果所以建议宏在书写的时候多些括号。
函数参数只在函数调用的时候求值一次它的结果值传递给函数。
表达式的求值结果更容易预测。
带
用的参数求值可能会产生不可预料的结果。
函数参数只在传参的时候求值一
一般来讲函数的宏的使用语法很相似。
所以语言本身没法帮我们区分二者。
//如果现存的一个名字需要被重新定义那么它的旧名字首先要被移除。
的编译器提供了一种能力允许在命令行中定义符号。
用于启动编译过程。
例如当我们根据同一个源文件要编译出一个程序的不同版本的时候这个特性有点用处。
假定某个
程序中声明了一个某个长度的数组如果机器内存有限我们需要一个很小的数组但是另外一个机器内存大些我们需要一个数组能够大些。
在编译一个程序的时候我们如果要将一条语句一组语句编译或者放弃是很方便的。
因为我们有条件编译指令。
比如说
OPTION1unix_version_option1();#endif#ifdef
OPTION2unix_version_option2();#endif#elif
OPTION2msdos_version_option2();#endif
查找策略先在源文件所在目录下查找如果该头文件未找到编译器就像查找库函数头文件一样在标准位置查找头文件。
filename.h查找头文件直接去标准路径下去查找如果找不到就提示编译错误。
但是这样做查找的效率就低些当然这样也不容易区分是库文件还是本地文件了。
comm.h和comm.c是公共模块。
test1.h和test1.c使用了公共模块。
test2.h和test2.c使用了公共模块。
test.h和test.c使用了test1模块和test2模块。
这样最终程序中就会出现两份comm.h的内容。
这样就造成了文件内容的重复。
当头文件在多个源文件中被包含时避免多次包含同一个头文件是很重要的。
否则可能导致重复定义的错误。
(如果未定义)检查是否已经定义了指定的宏若未定义则执行下面的代码块。
define
MY_HEADER_H当第一次包含头文件时MY_HEADER_H
宏还未定义因此代码块会被执行并且定义了该宏。
后续再次包含头文件时ifndef
用尖括号括起来的头文件包含指令通常用于包含标准库的头文件或系统提供的头文件。
编译器会在系统的标准头文件中搜索不会覆盖本地头文件。
用双引号括起来的头文件包含指令通常用于包含用户自定义的头文件。
编译器会先在当前源文件所在中搜索。
当有相同名称的头文件同时存在于当前源文件时优先使用当前源文件目录下的头文件即本地头文件会覆盖系统标准头文件。
这里可以去看一下我之前写的文章里面讲解过文件包含的本质、预处理符号、#
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback