1.翻译环境和运行环境在 ANSI C 的任何⼀种实现中存在两个不同的环境。第一种是翻译环境在这个环境中源代码被转换为可执行的机器指令二进制指令第二种是执行环境它用于实际执行代码。1.1翻译环境翻译环境下源代码被转换为可执行的机器指令二进制指令。翻译环境由编译和链接俩个大的过程组成。编译又可以分解成1,预处理预编译、2,编译、3,汇编三个过程。编译.c文件经过编译器的处理生成.obj(.o)的目标文件。链接目标文件加上链接库在链接器的处理下生成可执行程序.exe。1.2执行环境用于实际执行代码。一般指操作系统。以GCC为例子拆解编译链接的过程:源代码.c和.h为后缀的文件经过预处理.c文件会生成.i为后缀的中间文件.i为后缀的文件经过编译会生成.s为后缀的中间文件.s文件经过汇编会生成.o为后缀的目标文件然后多个目标文件加上链接库经过链接器的处理生成可执行程序.exe。也就是说有如下过程C代码--预处理--编译--汇编--链接--可执行程序____________________________________________________________________以GCC编译器为例子所用到的指令预处理gcc test.c -E -o test.i //-o是output生成的意思编译: gcc test.i -S -o test.s 将c代码转换成汇编代码要进行语义分析...汇编gcc test.s -c -o test.o //将汇编代码转换成机器可执行的指令(二进制指令)2.预处理详解2.1预定义符号__FILE__//进⾏编译的源⽂件__LINE__//⽂件当前的⾏号__DATE__//⽂件被编译的⽇期__TIME__//⽂件被编译的时间__STDC__//如果编译器遵循ANSI C其值为1否则未定义printf(file:%s line:%d\n, __FILE__, __LINE__);2.2#define 定义常量//语法 #define name stuff //例子 #define MAX 1000 #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__ )// \为续航符,一行写不完可以用续航符多行2.3#define定义宏#define 机制包括了⼀个规定允许把参数替换到文本中这种实现通常称为宏macro或定义宏define macro。宏是纯粹的文本替换。#define name( parament-list ) stuff /* 其中的 parament-list 是⼀个由逗号隔开的符号表它们可能出现在stuff中。 注意 参数列表的左括号必须与name紧邻如果两者之间有任何空⽩存在参数列表就会被解释为stuff的 ⼀部分。 */ //例子,宏是纯粹的文本替换 //宏实现数的平方 #define SQUARE(x) x * x int main() { int a 5; int ret SQUARE(a); printf(%d\n,ret); return 0; }2.4带有副作用的宏参数当宏参数在宏的定义中出现超过⼀次的时候如果参数带有副作⽤那么你在使⽤这个宏的时候就可能出现危险导致不可预测的后果。副作⽤就是表达式求值的时候出现的永久性效果。x1;//不带副作⽤ x;//带有副作⽤(改变了x的值) //写一个宏求俩个数的较大值 #define MAX(x,y) (x) (y) ? (x) : (y) int main() { int a 3; int b 5; int ret MAX(a, b); //a中的为后置在三目运算符中先进行判断再自增。显然35,判断完后a,b各自自增一次为4、6 //又yx则执行:后表达式 b,先将b的值此时为6赋给ret 再自增为7 printf(ret %d\n, ret);//6 printf(a %d\n, a);//4 printf(b %d\n, b);//7 return 0; }2.5宏替换的规则在程序中扩展#define定义符号和宏时需要涉及几个步骤。在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号。如果是它们首先被替换。替换文本随后被插入到程序中原来文本的位置。对于宏参数名被他们的值所替换。最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号。如果是就重复上述处理过程。注意1宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏不能出现递归。2当预处理器搜索#define定义的符号的时候字符串常量的内容并不被搜索。2.6宏和函数的对比宏通常被应⽤于执行简单的运算。//⽐如在两个数中找出较⼤的⼀个时写成下⾯的宏更有优势⼀些。 #define MAX(a, b) ((a)(b)?(a):(b))那为什么不选择函数完成呢1用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜⼀筹。2更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于 来比较的类型。宏的参数是类型无关的。和函数相比宏的劣势1每次使用宏的时候⼀份宏定义的代码将插入到程序中。除非宏比较短否则可能大幅度增加程序的长度。2宏是没法调试的。3宏由于类型无关也就不够严谨。4宏可能会带来运算符优先级的问题导致程容易出现错。宏有时候可以做函数做不到的事情。比如宏的参数可以出现类型但是函数做不到。#define MALLOC(num, type)\ (type )malloc(num sizeof(type)) ... //使⽤ MALLOC(10, int);//类型作为参数 //预处理器替换之后 (int *)malloc(10 sizeof(int));3.#和###运算符将宏的⼀个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。#运算符所执行的操作可以理解为字符串化。#define Print(n,format) printf(the value of #n is format\n,n) //#运算符 int main() { int a 1; Print(a,%d);//the value of a is 1 return 0; }##运算符可以把位于它两边的符号合成⼀个符号它允许宏定义从分离的文本片段创建标识符。 ##被称为记号粘合。这样的连接必须产生⼀个合法的标识符。否则其结果就是未定义的。在实际开发过程中##使⽤的很少很难举出恰当例子。#define GENERIC_MAX(type) \ type type##_max(type x,type y) \ { \ return (xy?x:y); \ } GENERIC_MAX(int) GENERIC_MAX(float) int main() { int m int_max(2,3); printf(%d\n,m); float fm float_max(3.5f, 4.5f); printf(%.2f\n,fm); return 0; }4.命名约定⼀般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分⼆者。那我们平时的⼀个习惯是:把宏名全部大写函数名不要全部大写这只是大部分情况也有宏是全小写如offestof用来计算结构体成员相较于结构体起始位置的偏移量5.#undef这条指令用于移除⼀个宏定义。#undef NAME //如果现存的⼀个名字需要被重新定义那么它的旧名字⾸先要被移除。6.条件编译在编译⼀个程序的时候我们如果要将⼀条语句⼀组语句编译或者放弃是很方便的。因为我们有条件编译指令。//比如调试性的代码删除可惜保留⼜碍事所以我们可以选择性的编译。 #include stdio.h #define __DEBUG__ int main() { int i 0; int arr[10] {0}; for(i0; i10; i) { arr[i] i; #ifdef __DEBUG__ printf(%d\n, arr[i]);//为了观察数组是否赋值成功。 #endif //__DEBUG__ } return 0; }常见条件编译指令1. #if 常量表达式 //若if后常量表达式为假则不执行 //... #endif //常量表达式由预处理器求值。 如 #define __DEBUG__ 1 #if __DEBUG__ //.. #endif #if 0 //##运算符 #define GENERIC_MAX(type) \ type type##_max(type x,type y) \ { \ return (xy?x:y); \ } GENERIC_MAX(int) GENERIC_MAX(float) int main() { int m int_max(2,3); printf(%d\n,m); float fm float_max(3.5f, 4.5f); printf(%.2f\n,fm); return 0; } #endif 2.多个分⽀的条件编译 #if 常量表达式 //... #elif 常量表达式 //... #else //... #endif 3.判断是否被定义 #if defined(symbol) #ifdef symbol #if !defined(symbol) #ifndef symbol 4.嵌套指令 #if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif7.头文件的包含7.1头文件被包含的方式本地文件包含 #include filename查找策略先在源文件所在目录下查找如果该头文件未找到编译器就像查找库函数头文件⼀样在标准位置查找头文件。如果找不到就提示编译错误。库文件包含 #include filename.h查找头文件直接去标准路径下查找若找不到就提示编译错误。7.2嵌套文件包含我们已经知道 #include指令可以使另外⼀个文件被编译。就像它实际出现于#include指令的地方⼀样。这种替换的方式很简单预处理器先删除这条指令并用包含文件的内容替换。⼀个头文件被包含10次那就实际被编译10次如果重复包含对编译的压力就比较大。为了解决这个问题在头文件中写入下行代码就可避免头文件被重复编译。#pragma once
企业数字化 ERP 产品动态
相关推荐
KubeVela KEP-2.4 解读:Dispatcher 可插拔交付机制与跨集群分发设计 云原生DevOps运维微服务 【免费下载链接】kubevela The Modern Application Platform. 项目地址: https://gitcode.com/gh_mirrors/ku/kubevela 点击查看 免费下载 本文基于 design/vela-core/keps/2.4-dispatchers/README.md 整理。该 KEP 当前标注为 Drafting&am… · 2026/9/27 10:23:43
Thonny在树莓派上的窗口机制与性能调优指南 1. 为什么树莓派用户总在Thonny里卡住——不是IDE太慢,是窗口逻辑没吃透你刚把树莓派4B插上电,烧好Raspberry Pi OS,双击桌面那个蓝色图标打开Thonny,结果发现:代码能写,但“运行”按钮点了没反应ÿ… · 2026/9/27 10:23:43
工业控制器分级存储方案:EEPROM、NOR Flash与SD卡分工实践 做工业控制器这些年,最让我头疼的不是算法,不是通信,而是“数据到底存在哪儿”。设备要保存的参数、固件、FPGA 配置文件、运行日志、历史曲线,数据性质完全不同——有的几天才改一次,有的每秒都在写,有的丢… · 2026/9/27 10:23:43
嵌入式驱动开发核心解析:从裸机寄存器到Linux设备树 都说嵌入式是个坑,可每年还是有一堆人往里头跳。我这几年一直在跟嵌入式驱动打交道,面试过不少应届生,也带过几个新人,发现大家对"驱动开发到底忙啥"这件事,普遍没搞清楚。有的是被网上那些"驱动开发月… · 2026/9/27 11:17:54
开网站程序别瞎写,这套保姆级建站教程让排名飙升 开网站程序别瞎写,这套保姆级建站教程让排名飙升 网站做好了没人访问,这是最让人头疼的事。代码写得再漂亮,搜索引擎看不见就是白搭。很多设计师转前端的朋友,技术底子不错,但一碰 SEO 就晕。别急,这篇保姆级建站教程专为你定制。… · 2026/9/27 11:17:54
2026最新乌克兰网站设计避坑指南:备案与选型全解析 2026最新乌克兰网站设计避坑指南:备案与选型全解析 做跨境建站,最怕的不是代码报错,而是政策合规的一头雾水。很多做乌克兰市场的站长,还没写完第一行HTML,就被复杂的备案流程和服务器合规搞得焦头烂额,完全不知道该怎么下手。这种“备案流程一… · 2026/9/27 11:17:48
网站代码是多少一文搞懂 网站代码是多少一文搞懂 域名服务器搞不懂?别慌,新手建站最头疼的就是这俩。今天用大白话,带你一文搞懂,从代码到底层逻辑,全讲透。… · 2026/9/27 11:17:41
ARM+FPGA交期52周?从选型到供应链的实战应对策略 做硬件的朋友应该都遇到过这种时刻:选型时看中一颗进口ARMFPGA,性能合适、外设齐全、功耗可控,价格也卡在预算线内,高高兴兴把方案定了,画板、调板、联调一路顺风顺水。等到了量产下单那一步,采购悠悠来一句… · 2026/9/27 11:17:29
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01