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.rhkb.cn/news/168149.html

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

相关文章

VUE到底有什么好处?

网上有许多前端开发框架的对比&#xff0c;相对的&#xff0c;VUE在综合评分方面还是优秀的。以下是一些State of JavaScript调查数据结果&#xff1a; 使用率&#xff1a;VUE使用者在调研开发者中占比 51%&#xff1b; 开发者满意度&#xff1a;VUE的综合开发者满意度达到64%…

springcloud笔记 (8) -网关 Gateway

网关 出国需要过海关 网关&#xff1a;网络的关卡 网关的作用 1&#xff1a;路由转发 2&#xff1a;安全控制 保护每个服务&#xff0c;不需要将每个暴露出去 3&#xff1a;负载均衡 1.没有网关&#xff1a;客户端直接访问我们的微服务&#xff0c;会需要在客户端配置很多…

ZooKeeper下载、安装、配置和使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

用“价值”的视角来看安全:《构建新型网络形态下的网络空间安全体系》

文章目录 写在前面安全认知的硬核概念威胁的演化路径与发展趋势构建网络空间安全体系好书推荐 写作末尾 写在前面 网络空间安全体系是建立在先进技术、严密监控和综合策略之上的综合性框架&#xff0c;旨在保护网络免受恶意攻击、数据泄露和网络犯罪的威胁&#xff0c;其核心包…

window11安装Python环境

python环境安装 访问Python官网:https://www.python.org/ 点击downloads按钮&#xff0c;在下拉框中选择系统类型(windows/Mac OS/Linux等) 选择下载最新版本的Python cmd命令如果出现版本号以及>>>则表示安装成功 如果出现命令行中输入python出现如下错误 可能…

现在大火的低代码是怎么回事?进来聊聊低代码

一、前言 开发过程中&#xff0c;只是觉得前端后端合起来&#xff0c;有很多冗余信息&#xff0c;被代码一遍遍重复表达&#xff0c;是一件很枯燥、无聊的事情。 这些枯燥的重复工作&#xff0c;完全可以由机器来做&#xff0c;以便解放出我们的时间&#xff0c;来做更有价值的…

wordpress搬家后,更改固定链接404文章无法打开,找不到网页与解决办法

出现这个问题的原因可能是服务没有设置伪静态设置&#xff0c;需要配置nginx服务器或者apach服务器 1.问题描述 WordPress中修改固定链接&#xff0c;如下。 保存后再打开网页出现类似于如下404错误。 2.解决办法 打开Nginx的配置文件(如果你没有自己写过那就是默认的nginx.…

sql server2014如何添加多个实例 | 以及如何删除多个实例中的单个实例

标题sql server2014如何添加多个实例 前提&#xff08;已安装sql server2014 且已有默认实例MSSQLSERVER&#xff09; 添加新的实例 其实就是根据安装步骤再安装一次&#xff08;区别在过程中说明&#xff09; 双击安装 选择“全新独立安装或添加现有功能” 然后下一步下一…

博客后台模块续更(五)

十一、后台模块-菜单列表 菜单指的是权限菜单&#xff0c;也就是一堆权限字符串 1. 查询菜单 1.1 接口分析 需要展示菜单列表&#xff0c;不需要分页。可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询。菜单要按照父菜单id和orderNum进行排序 请求方式 请求路径…

【数据结构】——二叉树的基础知识

数概念及结构 数的分类 二叉树、多叉树 数的概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做树的原因是它看起来像一颗倒挂的树&#xff0c;也就是说它是跟朝上&#xff0c;而叶朝下的。 有一个特殊的节点&…

java读取指定文件夹下的全部文件,并输出文件名,文件大小,文件创建时间

import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.*; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { try { Path startingDir Paths.get("你的目…

Spring中动态代理设计模式

目录 一、什么是动态代理 二、动态代理开发步骤 2.1 搭建开发环境 2.2 具体过程 三、动态字节码技术 四、动态代理开发简化代理开发 一、什么是动态代理 其实不管是静态代理还是动态代理其本质都是一样的&#xff0c;都是通过代理类为目标类增加额外功能&#xff0c;从而方便目…

自然语言处理---Transformer模型

Transformer概述 相比LSTM和GRU模型&#xff0c;Transformer模型有两个显著的优势&#xff1a; Transformer能够利用分布式GPU进行并行训练&#xff0c;提升模型训练效率。 在分析预测更长的文本时&#xff0c;捕捉间隔较长的语义关联效果更好。 Transformer模型的作用 基于seq…

蓝桥杯每日一题0223.10.23

第几天 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 简单枚举&#xff08;用k来记录经过的天数&#xff09; #include<bits/stdc.h> using namespace std; bool is_ren(int n) {if(n % 400 0 || (n % 4 0 && n % 100 ! 0))return true;return false; } int …

【Android知识笔记】Webview专题

WebView 核心组件 类名作用常用方法WebView创建对象加载URL生命周期管理状态管理loadUrl():加载网页 goBack():后退WebSettings配置&管理 WebView缓存:setCacheMode() 与JS交互:setJavaScriptEnabled()WebViewClient处理各种通知&请求事件should

为什么红黑树比AVL树效率高?

文章目录 前言红黑树的提出都知道的几个定义理解红黑树的高效总结 前言 红黑树为什么这么火呢&#xff1f;大家应该都很清楚&#xff0c;面试的时候不管三七二十一&#xff0c;就问你&#xff1a;什么是红黑树&#xff0c;为什么要用红黑树&#xff1f;就好像他很懂&#xff0…

CUDA学习笔记5——CUDA程序错误检测

CUDA程序错误检测 所有CUDA的API函数都有一个类型为cudaError_t的返回值&#xff0c;代表了一种错误信息&#xff1b;只有返回cudaSuccess时&#xff0c;才是成功调用。 cudaGetLastError()用来检测核函数的执行是否出错cudaGetErrorString()输出错误信息 #include <stdi…

项目快讯|深汕特别合作区气膜羽毛球馆正式开工

“永不坍塌”的气膜运动馆 “安全”是每个行业可持续发展的核心原则、是每个企业长久生存的重要底线、是每个人追求幸福生活的基本保障。 任何新行业、新技术、新材料、新工艺的发展都需要逐步规范化的企业标准、行业标准、国家标准。 气承膜技术发展的初期&#xff0c;面临行业…

springboot+vue基于Spark的共享单车数据存储系统的设计与实现【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

BadNets: Identifying Vulnerabilities in the Machine Learning Model Supply Chain

BadNets: Identifying Vulnerabilities in the Machine Learning Model Supply Chain----《BadNets:识别机器学习模型供应链中的漏洞》 背景&#xff1a; 许多用户将训练过程外包给云计算&#xff0c;或者依赖于经过训练的模型&#xff0c;然后根据特定的任务对模型进行微调。这…