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

【C语言复习】程序的编译与链接

程序的编译与链接

  • 写在前面
  • 程序的编译与链接
    • 编译的过程
      • 程序编译环境
      • 程序执行过程
      • 编译链接的过程
    • 预处理
      • 预处理符号
      • #define
      • 条件编译

写在前面

程序的编译与链接是C语言中非常重要的一节。关键点在于详解C语言的程序编译和链接、宏的定义和与函数的区别、条件编译等知识。

程序的编译与链接

编译的过程

程序编译环境

在ANSI C的任何一种实现中,存在两个不同的环境。

  • 翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  • 执行环境,用于实际执行代码。

程序执行过程

程序执行的过程:

  1. 程序首先要载入内存,再有操作系统的环境中,一般有操作系统完成。在独立的环境中,程序载入内存由人工安排,也可能是通过可执行代码置入只读内存中来完成。
  2. 程序的执行开始后,调用main函数。
  3. 开始执行程序代码,程序会使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储在静态内存中的变量在程序的整个执行过程中一直保存他们的值。
  4. 运行完代码,终止程序。可能是正常终止,也可能是意外终止。
  • 组成一个程序的每个源文件通过编译过程分别转换成目标代码。
  • 每个目标文件由链接器捆绑在一起,形成完整单一的可执行程序。
  • 链接器会引入标准C库中的所有用到的函数,也会搜索本地会用到的库,将程序所需要的函数也链接进入程序中。

编译链接的过程

test.c预编译阶段编译阶段汇编链接
以windows为例生成.i文件,执行预处理指令生成.s文件,负责语法、词法、语义分析和符号汇总生成可重定位目标文件.o文件,形成符号表,经过汇编指令到二进制指令到生成test.o的过程负责合并段表并进行符号表合并和符号表的重定向

如果我们在linux系统中编译.c文件,使用到的指令是:

gcc -o test.c test

如果我们想把这一个指令拆分成上面的阶段,让其分阶段进行,我们可以这样做:

gcc -E test.c -o test.i//预编译,生成.i文件
gcc -S test.c//编译,生成.s文件
gcc -c test.c//汇编,生成.o文件

预处理

预处理符号

在语言中一般内置一些预定义符号,如:

__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,值为1,否则未定义

#define

#define可以用来定义标识符,语法:

#define NAME stuff
//如:
#define MAX 100 
#define ZS zhangsan //为张三起简名
#define DO_CYCLICALLY for(;;) //用更容易理解的符号来替换一种实现。
//如果定义的stuff太长,可以分几行写,每行的后面都加上反斜杠。反斜杠的作用是续行。

#define可以定义宏,因为define机制规定:允许把参数替换到文本中。语法:

#define name(parament-list) stuff
//parament-list 是由逗号隔开的符号表,存放可能出现在stuff中的符号
//parament-list的左括号必须与name相邻。

注意,定义宏的时候,所有用于对数值表达式进行求值的宏都要加上括号,每个参数都要加,整体也要加括号,用来避免使用宏的时候由于参数的操作符或者外界的操作符优先级问题出现错误。

#define的替换规则:

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
  3. 最后,在此对结果文件进行扫描,看看是否包含任何由#define定义的符号。如果是,重复上面操作。

注意事项:

  1. 宏参数和#define定义中可以出现其他#define 定义的符号,但是对于宏,不能进行递归。

  2. 当预处理器搜索#define 定义的符号时,字符串常量的内容并不会被搜索。

使用技巧:

  1. 妙用宏定义函数
#define PRINT(FORMAT, VALUE)\printf("the value is "FORMAT"\n", VALUE);int main(){...PRINT("%d", 10);}

说明:只有当字符串作为宏参数的时候才可以把字符串放在字符串中。

  1. 使用#, 把宏参数变成对应的字符串。

    int i = 10;
    #define PRINT(FORMAT, VALUE)\printf("the value of "#VALUE" is "FORMAT "\n", VALUE);...PRINT("%d", i+3);
    

    代码中的#VALUE在预处理阶段会被处理为:“VALUE”。最终的输出结果时:

    the value of i+3 is 13
    
  2. 使用##,把位于##两边的符号合成一个新的符号。

    它允许宏定义从分离的文本片段创建标识符。

    #define ADD_TO_SUM(num, value)\sum##num += value;...ADD_TO_SUM(5,10);
    

    注意:这样的链接必须产生一个合法的标识符,否则结果是未定义的。

  3. 有的宏参数是带副作用的,可能会对自己或者其他的值产生影响。如果这个宏参数在宏的定义中出现超过一次,就会产生危险。副作用的意思是:表达是在求值时出现了永久性效果。举个例子:

    x + 1;
    x ++;
    

    其中x + 1 无副作用,因为并未改变x的值;但是x++改变了x的值,所以如果在宏定义中出现多次,就会影响x的正确取值,不注意会出现错误。

宏和函数的对比:

宏通常被应用在执行简单的运算。比如两个数中找较大。不用函数的原因是:

  1. 宏比函数在程序的规模和速度方面更胜一筹。
  2. 宏是无关类型的。而函数声明则必须声明为特定的类型(只针对C语言。)

宏的缺点:

  1. 每次使用宏,一份宏定义的代码会被插入到程序中去,所以宏一般只能定义短的代码,否则会大幅度增加程序的长度。
  2. 宏无法调试。无法递归。
  3. 宏正因为类型无关,所以不够严谨。
  4. 宏可能会带来运算符优先级的问题,从而导致程序错误。

命名约定:宏名全部大写,而函数名不要全部大写。

移除宏定义:

#undef NAME

条件编译

使用条件编译,在编译一个程序的时候,将一条语句编译或者放弃编译是很方便的。
比如:调试性的代码,可以选择性的编译。

#define __DEBUG__
int main()
{int i = 0;...#ifdef __DEBUG__...#endif __DEBUG__...
}

常见的条件编译:

  1. #if 常量表达式...
    #endif
    //常量表达式由预处理器求值。
    如:
    #define __DEBUG__ 1
    #if __DEBUG__
    ...
    #endif
    
  2. //多分支条件编译
    #if 常量表达式
    ..
    #elif#else#endif
    
  3. 判断是否被定义

    #if defined(symbol)
    #ifdef symbol#if !defined(symbol)
    #ifndef symbol
    
  4. 嵌套指令

相关文章:

【C语言复习】程序的编译与链接

程序的编译与链接写在前面程序的编译与链接编译的过程程序编译环境程序执行过程编译链接的过程预处理预处理符号#define条件编译写在前面 程序的编译与链接是C语言中非常重要的一节。关键点在于详解C语言的程序编译和链接、宏的定义和与函数的区别、条件编译等知识。 程序的编…...

Golang sql 事务如何进行分层

在写代码过程中遇到了需要使用gorm执行sql事务的情况,研究了一下各位大佬的实现方案,结合了自身遇到的问题,特此记录。 代码架构介绍 . ├── apis ├── config ├── internal │ ├── constant │ ├── controller │ ├──…...

linux系统openssh升级

linux系统openssh升级 说明 整个过程不需要卸载原先的openssl包和openssh的rpm包。本文的环境都是系统自带的openssh,没有经历过手动编译安装方式。如果之前有手动编译安装过openssh,请参照本文自行测试是否能成功。 如果严格参照本文操作,保…...

力扣-求关注者的数量

大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1729. 求关注者的数量二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.正确…...

近红外荧光染料修饰氨基IR 825 NH2,IR 825-Amine,IR-825 NH2

IR 825 NH2,IR 825-NH2,IR825 Amine,IR825-Amine,新吲哚菁绿-氨基,荧光染料修饰氨基产品规格:1.CAS号:N/A2.包装规格:10mg,25mg,50mg,包装灵活&am…...

Android Crash和ANR监控

文章目录一、Crash1.1 概念1.2 类型二、ANR2.1 概念2.2 类型2.2.1 KeyDispatchTimeout(常见)2.2.2 BroadcastTimeout2.2.3 ServiceTimeout2.2.4 ContentProviderTimeout三、测试中如何关注3.1 Crash测试关注方法3.2 ANR测试关注方法四、如何记录与处理4.…...

【02 赖世雄英语语法:复句的语法】

复句的语法复句:把单句 连在一起(标点符号,连词,关系词)1. 连接符号1.1 破折号 — :补充说明,同位语1.2 冒号 : (同位语)1.3 分号 ; ( , 连词)&am…...

北斗导航 | 多参考一致性监测算法(MRCC)(附伪码)—— B值计算

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== MRCC 用于接收机失效检查与排除。在进行 MRCC 之前,先判断 4 台接收机…...

数字孪生与 UWB 人员定位:双剑合璧的智能物联新时代

人员定位是指利用各种定位技术对人员在特定场所的位置进行准确定位的技术。人员定位技术主要应用于需要实时监控、管理和保障人员安全的场所,如大型厂区、仓库、医院、学校、商场等。人员定位技术的应用范围非常广泛,例如:-在工厂生产线上&am…...

奇点云DataSimba发版全解析:“企业级”版本升级,提供最佳组合

近日,奇点云发布数据云产品商业化版本的全新升级:DataSimba(数据云平台)提供极速版、专业版、旗舰版、红旗版,可靠性、可用性、可服务性再进阶,四大版本满足不同企业选择。 「乐高式DIY」or「最佳组合」&am…...

2-7 SpringCloud快速开发入门: Eureka 注册中心高可用集群搭建

接上一章节Eureka 服务注册中心发现与消费服务,这里讲讲Eureka 注册中心高可用集群搭建 Eureka 注册中心高可用集群搭建 Eureka 注册中心高可用集群就是各个注册中心相互注册 Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己&#xff0c…...

STL中的函数对象

STL-函数对象 函数对象概念 重载函数调用操作符的类,其对象常称为函数对象函数对象使用重载的()时,行为类似函数调用,也叫仿函数 本质 函数对象(仿函数)是一个类,不是一个函数—修改算法策略—采用虚拟对象调用 函数对象的使用理…...

linux下libevent的编译安装

1,官网下载最新的,https://libevent.org/2,将文件解压,虚拟机可以右键解压,也可以用命令解压,tar zxvf libevent.tar.gz,进行解压缩。这里压缩包的名称只是举例,实际它还会带上版本号…...

深度学习部署笔记(十): CUDA RunTime API-2.2流的学习

1. 流的定义 流(Stream)是一个基于上下文(Context)的任务管道抽象,是一组由GPU依次执行的CUDA操作序列,其中每个操作可能会使用或产生数据。在一个上下文中可以创建多个流,每个流都拥有自己的任…...

[ROC-RK3568-PC] [Firefly-Android] 10min带你了解I2C的使用

🍇 博主主页: 【Systemcall小酒屋】🍇 博主追寻:热衷于用简单的案例讲述复杂的技术,“假传万卷书,真传一案例”,这是林群院士说过的一句话,另外“成就是最好的老师”,技术…...

工作记录:举步维艰的在线 word 之旅 - tinymce

项目中需要实现 “在线编辑 word 模板” 的功能,我打算使用富文本组件 tinymce ,因为业务需求比较特殊,研究一下 tinymce 是否能实现。 如何在 vue 项目中引用 tinymce,可以看另一篇文章 《在 vue 项目中使用 tinymce》 &#x…...

动态规划编译距离

583. 两个字符串的删除操作方法:dp状态表示:以i-1和j-1为结尾的字符串world1和world2,抵达相同的字符串所需的最少操作数属性:最小值状态计算:world1[i-1]和world2[j-1]相同dp[i][j] dp[i-1][j-1];world1[i-1]和world…...

Netty 教程 – 解码器详解

TCP以流的方式进行数据传输,上层的应用为了对消息进行区分,往往采用如下方式 固定消息长度,累计读取到长度和定长LEN的报文后,就认为读取到了个完整的消息,然后将计数器位置重置在读取下一个报文内容将回车换行符作为…...

Allegro如何自动添加测试点操作指导

Allegro如何自动添加测试点操作指导 在做PCB设计的时候,在一些应用场合下需要给PCB上的网络添加测试点,如下图 测试点除了可以手动逐个添加之外,Allegro还支持自动添加测试点,具体操作如下 点击Manufacture点击Testprep...

【CSS】CSS 背景设置 ③ ( 背景位置-长度值设置 | 背景位置-长度值方位值同时设置 )

文章目录一、背景位置-长度值设置二、背景位置-长度值方位值同时设置三、完整代码示例一、背景位置-长度值设置 长度值设置 效果展示 : 设置背景位置为具体值 10px 50px : 粉色区域是盒子的区域 , 图片背景位于盒子位置 x 轴方向 10 像素 , y 轴方向 50 像素 ; 在水平方向上 ,…...

AbTest —— 不同场景下的应用模式

文章目录不同人群眼中的 AbTestAbTest 不同的功能倚重用户关联性弱,经典场景为 Feed - 部门组织形式大多非垂直业务用户关联性强,经典场景为 垂类/工具类APP;部门组织形式大多为垂直业务康为定律-组织决定产品形态不同应用模式下服务构建开机…...

fast-api 一款快速将spring的bean发布成接口并生产对应swagger文档调试的轻量级工具

fast-api简介背景开发痛点:分析需求实战fast-api快速上手1. 引入依赖2. FastApiMapping标记service对象3. swagger2/knife4j 在线测试进阶使用开启调试模式支持指定类或包目录发布如何关闭fast-api自定义fast-api的前缀写在最后简介 fast-api 一款快速将spring的bean(service)发…...

以公益之名 让人类发现数学之美

目录 1.品牌理念高举高打 2.创新赛制 赋能品牌 3.全球化的品牌传播 9月26日,2022阿里巴巴全球数学竞赛获奖名单公布,4座金杯分别由平均年龄25岁,来自美国麻省理工学院、美国布朗大学、北京大学在读数学博士斩获。77位获奖者中00后超五成引热…...

JUC并发编程之HashMap(jdk1.7版本)-底层源码探究

目录 JUC并发编程之HashMap(jdk1.7版本)-底层源码探究 HashMap底层源码 - jdk1.7 基本概念 -采取层层递进,问答式 存储Key-Value的结构 常量和成员变量 构造方法 put方法 inflateTable方法 hash方法 indexFor方法 addEntry方法 resize方法 createEntry…...

QT Q_OBJECT 和 signals/slots

Q_OBJECT宏展开 #define Q_OBJECT \ public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \virtual const QMetaObject *metaObject() const; \virtual void *qt_metacast(const char *); \virtual int qt_metacall(QMetaOb…...

APM新添加UAVCAN设备

简介 UAVCAN是一种轻量级协议,旨在通过CAN总线在航空航天和机器人应用中实现可靠通信。要实现通信,最基本需要data_type_ id, signature、数据结构、设备程序初始化。 添加设备数据结构文件(.uavcan格式) 1.在以下路径添加设备数据结构文件,根据设备类…...

【C++】string类基本用法

文章目录string类基本用法1. 为什么要学习string类?1.1 C语言中的字符串2. 标准库中的string类2.1 string类2.2 string类的常用接口说明小试牛刀1. 仅仅反转字母2. 字符串中第一个唯一字符3. 字符串中最后一个单词的长度string类基本用法 1. 为什么要学习string类&…...

KDZD耐电压高压击穿强度测试仪

一、技术参数 01、输入电压: 交流 220 V。 02、输出电压: 交流 0--50KV ; 直流 0—50kv 。 03、电器容量:3KVA。 04、高压分级:0—50KV,(全程可调)。 05、升压速率:0.1KV/s-…...

数组和指针面试题的补充(细的抠jio)

生命是一条艰险的峡谷&#xff0c;只有勇敢的人才能通过。 ——米歇潘 说明&#xff1a;用的vs都是x86的环境&#xff0c;也就是32位平台。 建议&#xff1a;对于难题来说&#xff0c;一定要配合画图来解决问题。 第一题&#xff1a; #include<stdio.h> int…...

Java多线程基础

文章目录Java多线程基础一、什么是进程与线程&#xff1f;二、线程和进程的区别【重点】三、线程的创建方式【重点】1. 继承Thread类2. 实现Runnable接口3. lambda 表达式四、Thread的常见属性线程中断自己定义一个标志位Thread类提供的静态方法线程的状态Java多线程基础 一、…...

龙信建设集团网站/企业网站推广策划书

DELPHI新版本WEBSERVICE&#xff0c;不仅可以编译成ISAPI DLL&#xff0c;依靠IIS部署&#xff0c; 并且还可以编译成单独的EXE&#xff0c;不再依赖IIS就可以独立运行&#xff0c;这一点未尝不可以说是非常方便的改进。...

四川做网站公司/农大南路网络营销推广优化

雷电具有极大的破坏性&#xff0c;其电压高达数百万伏&#xff0c;瞬间电流可高达数十万安培。雷击所造成的破坏性后果体现于下列三种层次&#xff1a;1、设备损坏&#xff0c;人员伤亡&#xff1b;2、设备或元器件寿命降低&#xff1b;3、传输或储存的信号、数据&#xff08;模…...

兰州的网站建设/优化网站排名方法教程

协程 轻量级&#xff0c;通过goroutine实现协程使用方法&#xff1a;go 函数名&#xff1a;启动一个协程执行函数体 package mainimport ("fmt""time") func testRoutine() {fmt.Println("this is one routine!!!")}func main() {//执行协程g…...

企业网站制作公司合肥/红河网站建设

对象的分配&#xff1a;虚拟机遇到一个new指令时&#xff0c;就会去常量池里查找有没有该类的符号引用(比如&#xff1a;com.hgs.Test (类)的代号 &#xff1a;1号(就是符号))&#xff0c;如果没有&#xff0c;说明没有定义&#xff0c;则抛ClassNotFoundException;对象的分配顺…...

怎么自己网站搜不到了/如何用google搜索产品关键词

八公山区指纹智能锁专用高强度深度防水热熔胶水厂家工厂直销PUR(PolyurethaneReactive)中文全称为湿气固化反应型聚氨酯热熔胶。主要成分是端异聚氨酯预聚体。PUR的粘接性和韧性(弹性)可调节&#xff0c;并有着优异的粘接强度、耐温性&#xff0c;耐化学腐蚀性和耐老化性。已成…...

做海产品的外贸网站/信息流广告素材网站

转载&#xff1a; http://blog.ednchina.com/conan85420/431119/message.aspx 本程序首先输出目标地址空间的数据&#xff0c;然后连续发起两次DMA传输&#xff0c;最后再次输出DMA传输后目标地址空间的数据。第二次发起可以在第一次DMA传输没有结束的情况下开始&#xff0c;不…...