编译和链接(1)

news2024/11/16 13:52:30

目录

1. 程序的翻译环境和执行环境

2. 详解编译+链接

2.1 翻译环境

2.2 编译本身也分为几个阶段:

2.3 运行环境

3. 预处理详解

3.1 预定义符号

 3.2 #define

3.2.1 #define 定义标识符

3.2.2 #define 定义宏

3.2.3 #define 替换规则

3.2.4 #和##

1. 程序的翻译环境和执行环境

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

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。

第2种是执行环境,它用于实际执行代码。

2. 详解编译+链接

2.1 翻译环境

组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。

每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。

链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人 的程序库,将其需要的函数也链接到程序中。 

2.2 编译本身也分为几个阶段:

看代码:

sum.c

int g_val = 2016;
void print(const char *str)
{
 printf("%s\n", str);
}

test.c

#include <stdio.h>
int main()
{
 extern void print(char *str);
 extern int g_val;
 printf("%d\n", g_val);
 print("hello bit.\n");
 return 0;
}

如何查看编译期间的每一步发生了什么呢? 

test.c

#include <stdio.h>
int main()
{
 int i = 0;
 for(i=0; i<10; i++)
 {
 printf("%d ", i);
 }
 return 0;
}

1. 预处理 选项 gcc -E test.c -o test.i

        预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

2. 编译 选项 gcc -S test.c

        编译完成之后就停下来,结果保存在test.s中。

3. 汇编 gcc -c test.c

        汇编完成之后就停下来,结果保存在test.o中。

2.3 运行环境

程序执行的过程:

1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。

3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。

4. 终止程序。正常终止main函数;也有可能是意外终止。2. 程序的执行便开始。接着便调用main函数。

3. 预处理详解

3.1 预定义符号

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

这些预定义符号都是语言内置的。

举个例子:

printf("file:%s line:%d\n", __FILE__, __LINE__); 

 3.2 #define

3.2.1 #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__ ) 

提问:

        在define定义标识符的时候,要不要在最后加上 ; ?

比如:

#define MAX 1000;
#define MAX 1000

建议不要加上 ; ,这样容易导致问题。

比如下面的场景:

if(condition)
 max = MAX;
else
 max = 0;

这里会出现语法错误。

3.2.2 #define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。

下面是宏的申明方式:

#define name( parament-list ) stuff

其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。

注意:

参数列表的左括号必须与name紧邻。

如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

如:

#define SQUARE( x ) x * x

这个宏接收一个参数 x .

如果在上述声明之后,你把 

SQUARE( 5 );

置于程序中,预处理器就会用下面这个表达式替换上面的表达式:

5 * 5

警告:

这个宏存在一个问题:

观察下面的代码段:

int a = 5;
printf("%d\n" ,SQUARE( a + 1) );

乍一看,你可能觉得这段代码将打印36这个值。

事实上,它将打印11.

为什么? 

替换文本时,参数x被替换成a + 1,所以这条语句实际上变成了:

printf ("%d\n",a + 1 * a + 1 );

这样就比较清晰了,由替换产生的表达式并没有按照预想的次序进行求值。

在宏定义上加上两个括号,这个问题便轻松的解决了

#define SQUARE(x) (x) * (x)

这样预处理之后就产生了预期的效果: 

printf ("%d\n",(a + 1) * (a + 1) );

这里还有一个宏定义:

#define DOUBLE(x) (x) + (x) 

定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。

int a = 5;

printf("%d\n" ,10 * DOUBLE(a)); 

这将打印什么值呢?

warning:

看上去,好像打印100,但事实上打印的是55.

我们发现替换之后: 

printf ("%d\n",10 * (5) + (5));

乘法运算先于宏定义的加法,所以出现了

55 

这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。

#define DOUBLE( x)   ( ( x ) + ( x ) )

提示:

        所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于            参数中 的操作符或邻近操作符之间不可预料的相互作用。 

3.2.3 #define 替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

        1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它          们首先 被替换。

        2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

        3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就          重复上 述处理过程。

注意:

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

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

3.2.4 #和##

        如何把参数插入到字符串中?

首先我们看看这样的代码:

int i = 10;
#define PRINT(FORMAT, VALUE)\
 printf("the value of " #VALUE "is "FORMAT "\n", VALUE);
...
PRINT("%d", i+3);//产生了什么效果?

这里输出的是不是 hello bit ?

答案是确定的:

是。

我们发现字符串是有自动连接的特点的。 

1. 那我们是不是可以写这样的代码?:

#define PRINT(FORMAT, VALUE)\
 printf("the value is "FORMAT"\n", VALUE);
...
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

## 的作用 

        ##可以把位于它两边的符号合成一个符号。

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

#define ADD_TO_SUM(num, value) \
 sum##num += value;
...
ADD_TO_SUM(5, 10);//作用是:给sum5增加10.

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1377721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【昕宝爸爸小模块】深入浅出之Java 8中的 Stream

深入浅出之Java 8中的 Stream 一、&#x1f7e2;典型解析1.1 &#x1f7e0;Java 8中的Stream 都能做什么1.2 &#x1f7e0;Stream的创建 二、✅ Stream中间操作2.1 &#x1f7e0;Filter2.2 &#x1f7e0;Map2.3 &#x1f7e0;limit / skip2.4 &#x1f7e0;sorted2.5 &#x1…

基于LVGL编写的windows串口工具: LCOM

LCOM: Serial Port Tools based on LVGL (PC Software) 一直以来我都想用LVGL做一个真正意义上的PC软件&#xff0c;来验证或者表达LVGL出色的特性&#xff0c;现在我用LCOM做到了&#xff01; LCOM 是一个基于LVGL编写的串口工具&#xff0c;界面简洁&#xff0c;功能出色&a…

构建基于RHEL8系列(CentOS8,AlmaLinux8,RockyLinux8等)的Nginx1.24.0的RPM包

本文适用&#xff1a;rhel8系列&#xff0c;或同类系统(CentOS8,AlmaLinux8,RockyLinux8等) 文档形成时期&#xff1a;2022-2023年 因系统版本不同&#xff0c;构建部署应略有差异&#xff0c;但本文未做细分&#xff0c;对稍有经验者应不存在明显障碍。 因软件世界之复杂和个人…

二十四、同域名下JSESSIONID重叠导致退出

同域名下JSESSIONID重叠导致退出 近期在开发项目的时候发现,如果同域名的情况下,如果把一个单页面无登录系统嵌套进入另外一个系统,那么会出现相互退出的问题。 思考解决方案 一、清除掉嵌套的系统的JSESSIONID,意思就是嵌套系统不设置JSESSIONID 1找寻出问题接口 在无痕…

DHCP与时间同步

目录 一、DHCP 1、DHCP定义 1.什么是DHCP 2.DHCP的好处 3.DHCP的分配方式 4.为什么使用DHCP 5.DHCP模式 2、DHCP的工作过程 3、DHCP动态配置主机地址 1.DHCP服务的优点 2.可分配的地址信息 3.动态分配IP地址 二、时间同步 1、ntp 2、chrony 1、搭建本地本地时间…

011集:复制文件(包括exe、 jpg、png、Word、Excel和PPT等二进制文件)—python基础入门实例

在文本文件的内部以字符形式存储数据&#xff0c;字符是有编码的&#xff0c;例如GBK (简体中文) 、UTF-8等;在二进制文件的内部以字节形式存储数据、没有编码的概念。二进制文件较为常用&#xff0c;例如Windows中的exe、图片 (jpg、png等)&#xff0c;以及Word、Excel和PPT等…

多语言生成式语言模型用于零样本跨语言事件论证提取(ACL2023)

1、写作动机&#xff1a; 经过预训练的生成式语言模型更好地捕捉实体之间的结构和依赖关系&#xff0c;因为模板提供了额外的声明性信息。先前工作中模板的设计是依赖于语言的&#xff0c;这使得很难将其扩展到零样本跨语言转移设置。 2、主要贡献&#xff1a; 作者提出了一…

d2l动手学深度学习】 Lesson 13 Dropout层 老板随机丢掉一些做项目的程序员‍,项目的效果会更好!(bushi)

文章目录 1. 什么是Dropout老板随机丢掉一些做项目的程序员&#x1f9d1;‍&#x1f4bb;&#xff0c;项目的效果会更好&#xff01; 2. 代码实现&#xff08;不用torch&#xff09;3. 代码实现&#xff08;使用torch&#xff09;3. 调节实验3.1 老师上课所设置的dropout1, dro…

探索 hasOwnProperty:处理对象属性的关键(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

问界又“翻车”了? 新能源电池“怕冷”成短板

文 | AUTO芯球 作者 | 李欣 2023年12月17日&#xff0c;蔚来创始人李斌亲自下场&#xff01;驾驶ET7从上海出发&#xff0c;经过超14小时的行驶后&#xff0c;达成一块电池行驶超过1000公里的成绩&#xff0c;这一直播引起外界的广泛关注。 这不禁让人与”懂车帝冬测“联想到…

Vue3 的基本开发+新特性

Vue3 1.Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {data(){return {count:0}},methods:{addCount(){this.count}} } </script> <script setup> import { ref } from vue const count ref(0) const addCount ()> count.val…

文件操作(你真的会读写文件吗?)

文章目录 一、为什么使用文件&#xff1f;二、什么是文件&#xff1f;2.1 程序文件2.2 数据文件2.3 文件名 三、二进制文件和文本文件3.1 二进制文件3.2 文本文件 四、文件的打开和关闭4.1 流和标准流4.1.1 流4.1.2 标准流 4.2 文件指针4.3 fopen和fclose 五、文件的顺序读写5.…

代码随想录刷题第四十八天| 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

代码随想录刷题第四十八天 今天是打家劫舍三部曲&#xff0c;最后一题树形dp有点难&#xff0c;其他还好 打家劫舍 (LC 198) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def rob(self, nums: List[int]) -> int:dp [0 for _ in range(len(nums)1)]dp[1…

Open3D 截取感兴趣的点云部分

import time import open3d as o3d; import numpy as np; import matplotlib.pyplot as plt from scipy.signal import find_peaks#坐标 mesh_coord_frame o3d.geometry.TriangleMesh.create_coordinate_frame(size355, origin[0, 0, 0]) #mesh_coord_frame mesh_coord_frame…

机器学习_实战框架

文章目录 介绍机器学习的实战框架1.定义问题2.收集数据和预处理(1).收集数据(2).数据可视化(3).数据清洗(4).特征工程(5).构建特征集和标签集(6).拆分训练集、验证集和测试集。 3.选择算法并建立模型4.训练模型5.模型的评估和优化 介绍机器学习的实战框架 一个机器学习项目从开…

UVa1308/LA2572 Viva Confetti

题目链接 本题是2002年ICPC亚洲区域赛金沢(日本)赛区的H题 题意 我已经把n个圆盘依次放到了桌面上。现按照放置顺序依次给出各个圆盘的圆心位置和半径&#xff0c;问最后有多少圆盘可见&#xff1f;如下图所示。 分析 《训练指南》的题解&#xff1a; 题目说“保证在对输入数据…

87.乐理基础-记号篇-反复记号(一)反复、跳房子

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;86.乐理基础-记号篇-速度记号-CSDN博客 首先是反复记号表总结图&#xff1a; 当前是写前两个记号&#xff0c;其余记号后面写&#xff1a;这些反复记号最主要的目的很简单&#xff0c;还是为了节约纸张&#xff0c…

使用Linux安装Mysql Community Server 8.0.35

一、下载Mysql 官网&#xff1a;https://www.mysql.com/ 第一步&#xff1a;进入Linux官网&#xff0c;点击下载 第二步&#xff1a;点击MySQL Community (GPL) Downloads 第三步&#xff1a;进入页面&#xff0c;选择 MySQL Community Server 第四步&#xff1a;根据自己服务…

SpringBoot集成RabbitMq,RabbitMq消费与生产,消费失败重发机制,发送签收确认机制

RabbitMq消费与生产&#xff0c;消费失败重发机制&#xff0c;发送确认机制&#xff0c;消息发送结果回执 1. RabbitMq集成spring bootRabbitMq集成依赖RabbitMq配置RabbitMq生产者&#xff0c;队列&#xff0c;交换通道配置&#xff0c;消费者示例 2. RabbitMq消息确认机制消息…

LangChain 72 reference改变结果 字符串评估器String Evaluation

LangChain系列文章 LangChain 60 深入理解LangChain 表达式语言23 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 61 深入理解LangChain 表达式语言24 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 62 深入理解Lang…