ONEPIECE!程序环境和预处理——C语言最终章

时间过得飞快呀,从第一篇blog到现在,已经有三四个月的时间了,而我们终于也迎来了C语言的最终章——程序环境和预处理!加油吧朋友们,ONEPIECE就在眼前~

目录

 

一、程序的"翻译环境"和"运行环境"

 二、详解"编译环境"

三、"运行环境"

四、"预处理"详解

4.1预定义符号

4.2 小能手#define 

4.2.1 #define 定义标识符

4.2.2 #define 定义宏

4.2.3 #define 替换规则

4.2.4 巧用 # 和 ##

4.2.4.1 # 的使用

4.2.4.2 ##的使用

 4.2.5 带副作用的宏参数

4.2.6 宏和函数的对比

4.3 #undef

 4.4 条件编译

4.5文件包含

4.5.2 嵌套文件包含


 一、程序的"翻译环境"和"运行环境"

在ANSIC的任何一种实现中,存在两个不同的环境:

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

test.c是文本信息的代码——源代码 || test.exe是可执行程序——二进制的指令

 二、详解"编译环境"

编译环境其实又分为编译和链接两部分:编译由编译器执行、链接由链接器执行。

编译器和链接器我们都可以在我们的电脑中搜索到:

  

下面我们介绍一下程序的编译过程: 

1.组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
2.每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
3.链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

其实编译还可以继续细分:预编译、编译、汇编。

下面我们具体看一下每一步系统都干了些什么: 

我们可以看到几个阶段都强调了“符号”、“符号表”的操作,其实这些操作都是在为“链接”这个阶段做铺垫。

我们举个例子:假设我们的文件有两个 test.c 和 add.c


 符号汇总:

在 add.c 中,系统汇总了一个符号(系统一般只汇总应用全局的符号) add

在 test.c 中,系统汇总了符号:addmain、printf(这里忽略不谈) 

生成符号表:

注:这里汇总的每一个符号都是有其地址的,在这里我们假设一下。

合并段表:

而且,目标文件都有其特定的格式,在合并符号表时,相同段的数据会合并到一起:

合并符号表: 

合并两个符号表时,将 add.c 和 test.c 中的符号表合并到一起:

 最终系统都是通过最后这个符号表记录的地址来找到对应的符号位置。

三、"运行环境"

程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。                                                                                3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。

四、"预处理"详解

经过上面的学习,我们可能已经忘了,"预处理"是哪个阶段来着?

它是"编译"的第一个小阶段。 

4.1预定义符号

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

用例: 

int main()
{printf("%s\n", __FILE__);//进行编译的文件printf("%d\n", __LINE__);//文件当前的行号printf("%s\n", __DATE__);//文件被编译的日期printf("%s\n", __TIME__);//文件被编译的时间//printf("%d\n", __STDC__);//当前使用是的VS2022不遵循ANSI Creturn 0;
}

4.2 小能手#define 

4.2.1 #define 定义标识符

语法:
#define name stuff

注意:define定义标识符时,最后不要加 ; 因为系统是完全把 stuff 替换到 name的位置。

相信小伙伴们对定义标识符已经很熟悉啦,下面我们来新介绍一个语法:

4.2.2 #define 定义宏

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

下面是宏的申明方式:

#define name( parament-list ) stuff

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

注意:
参数列表的左括号必须与name紧邻

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

举个栗子:

#define ADD(x, y) (x) + (y)
int main()
{printf("%d\n", ADD(3, 22));return 0;
}

是不是很神奇,用宏也可以做函数的工作,但是宏在传参时也有可能会发生小错误:

 其实宏能做的不只是这些,宏能替换大部分的函数。

4.2.3 #define 替换规则

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

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。//检查宏中是否存在其他#define并替换
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

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

注意:

1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

4.2.4 巧用 # 和 ##

4.2.4.1 # 的使用

使用 # ,把一个宏参数变成对应的字符串

#define PRINT(x,format) printf(#x "的值是:"format"\n", x)
int main()
{float Love_date = 3.22;PRINT(Love_date, "%.2f");return 0;
}

4.2.4.2 ##的使用

##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。

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

 4.2.5 带副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果
例如:

x + 1;  //不带副作用
x++;    //带有副作用

4.2.6 宏和函数的对比

宏的优点:

1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。
    所以宏比函数在程序的规模和速度方面更胜一筹
2. 更为重要的是函数的参数必须声明为特定的类型,  宏是类型无关的
    所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点      型等可以用于>来比较的类型。

宏的缺点:

1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。

    除非宏比较短,否则可能大幅度增加程序的长度(每使用一次都要替换一次)。
2. 宏是没法调试的。宏直接替换,我们无法逐步分析。

3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错

另外,为了区分宏和函数,在宏和函数的命名时,宏一般全大写,如MAX、DOUBLE...;而函数名不全大写。

4.3 #undef

#undef 用于移除一个宏定义

 4.4 条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。

常见的条件编译指令:

1.(同if else)

#if  常量表达式

//操作

#endif
//常量表达式由预处理器求值。

如:

#if 1printf("u r a genius!\n");
#endif
//...

2.多个分支的条件编译(同if elseif else)
#if 常量表达式
//...
#elif 常量表达式    //可以无限多
//...
#else
//...
#endif        //结束标志,必须有

3.判断是否被定义
#if defined(symbol)
#ifdef symbol

//以上两种写法相同
#if !defined(symbol)
#ifndef symbol

//以上两种写法相同

4.嵌套指令
#if defined(OS_UNIX)
    #ifdef 条件1
        //...
   
#endif
   
#ifdef 条件2
        //...
 
  #endif

#elif defined(OS_MSDOS)
    #ifdef 条件3
        //...
 
  #endif
#endif

4.5文件包含

4.5.1 头文件被包含的方式

头文件的包含有2中形式:

1.包含本地文件(自己的.h文件)

#include"xxx.h"

2.包含标准库的头文件

#include<xxx.h>

本地文件查找:

先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件;如果找不到就提示编译错误。
 

标准库文件查找:

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

4.5.2 嵌套文件包含

当出现以上这种场景时,就造成了文件内容的重复。 

这时我们就可以使用条件编译。或者在VS中我们创建.h文件中,它也会生成#pragma once ,这也可以避免头文件的重复引入。

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

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

相关文章

Biotech - 环状 mRNA 的 LNP 递送系统 与 成环框架

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/133992971 环状 RNA&#xff08;或 circRNA &#xff09;是一种单链 RNA&#xff0c;与线性 RNA 不同&#xff0c;形成一个共价闭合的连续环。在环…

Hadoop+Hive+Spark+Hbase开发环境练习

1.练习一 1.数据准备 在hdfs上创建文件夹&#xff0c;上传csv文件 [rootkb129 ~]# hdfs dfs -mkdir -p /app/data/exam 查看csv文件行数 [rootkb129 ~]# hdfs dfs -cat /app/data/exam/meituan_waimai_meishi.csv | wc -l 2.分别使用 RDD和 Spark SQL 完成以下分析&#xf…

零代码编程:用ChatGPT多线程批量将PDF文档转换为word格式

pdf2docx是Python的一个库&#xff0c;可以很方便的将PDF文档转换为word格式&#xff0c;首先安装这个库。 然后在ChatGPT中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个文档格式转换的任务&#xff0c;具体步骤如下&#xff1a; 打开F盘的Books文件…

强化学习代码实战(1)

机器人领域&#xff1a;控制&#xff0c;规划&#xff0c;感知等都可以用&#xff0c;可以把它作为一个优化过程&#xff0c;那么任何需要优化的问题都可以用它解决。 1.应用 深度学习&#xff1a;智能感知&#xff0c;解决智能如何理解这个世界的问题。 强化学习&#xff1a…

python之代理ip的配置与调试方法详解

代理IP在Python中是一种强大的工具&#xff0c;它可以用于隐藏真实IP地址、绕过访问限制、提高数据爬取和网络请求的效率等。下面将详细介绍Python中代理IP的配置与调试方法&#xff0c;帮助您更好地理解和应用代理IP。 1. 选择合适的代理IP 在使用代理IP之前&#xff0c;需要…

vue v-for

目录 前言&#xff1a;Vue.js 中的 v-for 指令 详解&#xff1a;v-for 指令的基本概念 用法&#xff1a;v-for 指令的实际应用 1. 列表渲染 2. 动态组件 3. 表单选项 4. 嵌套循环 5. 键值对遍历 解析&#xff1a;v-for 指令的优势和局限性 优势&#xff1a; 局限性&a…

网络通信和tcp协议

一、计算机网络架构模型 1、OSI七层模型 2、TCP/IP模型 3、TCP/IP协议族 无论是什么网络模型&#xff0c;都是为上一层提供服务&#xff0c;抽象层建立在低一层提供的服务上&#xff0c;每层都对应不同的协议 4、地址和端口号 1&#xff09;MAC地址 MAC 地址共 48 位&#…

RAM(recognize anything)—— 论文详解

一、概述 1、是什么 RAM 论文全称 Recognize Anything: A Strong Image Tagging Model。区别于图像领域常见的分类、检测、分割&#xff0c;他是标记任务——即多标签分类任务&#xff08;一张图片命中一个类别&#xff09;&#xff0c;区分于分类&#xff08;一张图片命中一个…

Java基础(第一期):IDEA的下载和安装(步骤图) 项目结构的介绍 项目、模块、类的创建。第一个代码的实现

文章目录 IDEA1.1 IDEA概述1.2 IDEA的下载和安装1.2.1 下载1.2.2 安装 1.3 IDEA中层级结构介绍1.3.1 结构分类1.3.2 结构介绍project&#xff08;项目、工程&#xff09;module&#xff08;模块&#xff09;package&#xff08;包&#xff09;class&#xff08;类&#xff09; …

【Javascript】等于与全等于

var a1;if(a1){console.log(你好&#xff01;&#xff01;);} 如果a赋值为 1 的时候 var a1;if(a1){console.log(你好&#xff01;&#xff01;);}仍然会执行 console.log(你好&#xff01;&#xff01;); 所以在开发中如果if语句里要使用等于的时候使用 var a1;if(a1)…

基于Java的疫苗接种管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

LeetCode 11. 盛最多水的容器

盛水最多的容器 题目链接 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。…

2023 uniapp( vue3)使用canvas生成海报并保存,taro/微信小程序也适用

有段时间没写vue了&#xff0c;有点生疏了...... 1、代码有注释&#xff0c;完整代码如下 <template><view class"page"><canvas class"canvas" v-if"isShow" :style"{width:${canvasWidth}px,height:${canvasHeight}px}&…

uni-app 小宠物 - 会说话的小鸟

在 template 中 <view class"container"><view class"external-shape"><view class"face-box"><view class"eye-box eye-left"><view class"eyeball-box eyeball-left"><span class"…

【通览一百个大模型】Baize(UCSD)

【通览一百个大模型】Baize&#xff08;UCSD&#xff09; 作者&#xff1a;王嘉宁&#xff0c;本文章内容为原创&#xff0c;仓库链接&#xff1a;https://github.com/wjn1996/LLMs-NLP-Algo 订阅专栏【大模型&NLP&算法】可获得博主多年积累的全部NLP、大模型和算法干货…

Delphi 编程实现拖动排序并输出到文档

介绍&#xff1a;实现拖动排序功能&#xff0c;并将排序后的内容输出到文档中。我们将使用 Delphi 的组件来创建一个界面&#xff0c;其中包括一个 Memo 控件用于输入内容&#xff0c;一个 ListBox 控件用于显示排序后的内容&#xff0c;并且提供按钮来触发排序和输出操作。 代…

常用Win32 API的简单介绍

目录 前言&#xff1a; 控制控制台程序窗口的指令&#xff1a; system函数&#xff1a; COORD函数&#xff1a; GetStdHandle函数&#xff1a; GetConsoleCursorInfo函数&#xff1a; CONSOLE_CURSOR_INFO函数&#xff1a; SetConsoleCursorInfo函数&#xff1a; SetC…

解决“您点击的链接已过期”;The Link You Followed Has Expired的问题

今天WP碰到一个坑。无论发布文章还是更新插件、更换主题都是这么一种状态“您点击的链接已过期”&#xff1b;The Link You Followed Has Expired 百度出来的答案都是修改post_max_size 方法1. 通过functions.php文件修复 这种方法更容易&#xff0c;只需将以下代码添加到Wor…

maven仓库改国内源

今天准备复现漏洞环境&#xff0c;发现太慢&#xff0c;需要配置国内源 file -> settings 搜索maven 修改settings.xml&#xff0c;这里的需要修改两个文件 1.上图的settings.xml文件 2.idea的maven模块 settings.xml文件将原来的注释掉&#xff0c;然后把阿里的添加上&…

Web前端—Flex布局:标准流、浮动、Flex布局、综合案例(短视频首页解决方案)

版本说明 当前版本号[20231024]。 20231024初版 目录 文章目录 版本说明目录Flex布局01-标准流02-浮动基本使用产品区域布局HTML标签CSS样式 清除浮动场景搭建额外标签法单伪元素法双伪元素法overfow法 03-Flex布局Flex组成主轴对齐方式侧轴对齐方式修改主轴方向弹性伸缩比弹…