适合小白学习预处理与程序环境,这篇文章就够了

news2024/11/17 13:33:18

目录

一. 前言

二. 正文

2.1 “冷知识”:程序环境

2.21 翻译环境——程序从无到有:程序编译 + 链接

2.22 运行环境——程序开跑

2.3  那些鲜为人知:预定义符号

2.4  预处理指令 #define

2. 41 #和## —— 

2.42  宏和函数优劣对比

2.5  #undef:  终结宏

2.6  鸡肋——条件编译(底层对库进行修改使用比较广泛)

2.7  文件包含#include

2. 71 如何解决头文件多重包含?

三. 结语


一. 前言

        本小节跟大家分享预处理与程序环境的相关知识,希望能给大家带来帮助。

二. 正文

2.1 “冷知识”:程序环境

        在 ANSIC 的任何一种实现中,存在两个不同的环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代 码。

2.21 翻译环境——程序从无到有:程序编译 + 链接

 如图这是程序由人写的源代码——>机器所能阅读的机器语言的过程图:

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

        

 以上我们对程序编译+链接有了初步的认识,下面是其中的详细步骤,及各步骤的功能,如图:

2.22 运行环境——程序开跑

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

2.3  那些鲜为人知:预定义符号

预定义符号
这些预定义符号都是语言内置的。
比如:
__FILE__       // 进行编译的源文件
__LINE__     // 文件当前的行号
__DATE__     // 文件被编译的日期
__TIME__     // 文件被编译的时间
__STDC__     // 如果编译器遵循 ANSI C ,其值为 1 ,否则未定义
举个栗子:
printf ( "file:%s line:%d\n" , __FILE__ , __LINE__ );

2.4  预处理指令 #define

这里就是我们最熟悉的#define 了,

用法1:

#define name stuff     (注:这里后面不要加分号“;”,因为在预编译时,stuff会替换程序中所有的name,所以你要的是stuff,不是stuff;)

用法2:

#defifine 定义宏
#defifine 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(defifine macro)。
下面是宏的申明方式:
#define name( parament - list ) stuff 其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在stuffff中。
注意:
1. 参数列表的左括号 必须 name 紧邻 。 如果两者之间有任何空白存在,参数列表就会被解释为 stuff 的一部分。
比如:
#define SQUARE( x )    x * x  // 正确的写法
2. 替换目标尽量用括号包裹,避免出现运算顺序错误。
#define text(x, y)     x + y          // 高危代码,非常容易发生错误
//  比如:printf("%d", 2 * text(2, 3));   // 输出是:7   而你想要的是10,所以正确的写法应该是
#define text(x, y)     ((x) + (y)) 
//  所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号避免在使用宏时由于参数中的操作符或
邻近操作符之间不可预料的相互作用
注意:
1. 宏参数和 #define 定义中可以出现其他 #define 定义的变量。但是对于宏,不能出现递归
2. 当预处理器搜索 #defifine 定义的符号的时候,字符串常量的内容并不被搜索

2. 41 #和## —— 

思考:如何把参数插入到字符串中?
首先我们看看这样的代码:
char* p = "hello ""bit\n";
    printf("hello ""bit\n");
    printf("%s\n", p);

 从结果上我们会发现都打印了 hello bit 。我们发现字符串是有自动连接的特点的。

   另外一个技巧是: 使用 # 把一个宏参数变成对应的字符串

比如:

第一种:#define text(x)  printf("I " "x" "China\n");  //参数x 需要是个字符串

第二种:#define text(x)  printf("I "#x"China\n");    // x同样要是字符串

## 的作用:
   ##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符。
#define ADD_TO_SUM(num, value)
sum##num += value;
...
ADD_TO_SUM(5, 10);// 作用是:给 sum5 增加 10.
注: 这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。

2.42  宏和函数优劣对比

性                                              #define 定义宏                                                                函数
代码长度           每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,      每次使 用这个函数时,都调用那个地方的同 一份代码
                         程序的长度会大幅度增长函数代码只出现于一个地方;
执行速度                                             更快                                                                     存在函数的调用和返回的额外开销,所以相对慢一些
操作符优先级        宏参数的求值是在所有周围表达式的上下文环境里,                       函数参数只在函数调用的时候求值一次,它的结果值传递
                              除非加上括号,否则邻近操作符的优先级可能会产生                       给函数。表达式的求值结果更容易预测。 
                              不可预料的后果,所以建议宏在书写的时候多些括号。                                                              
带有副作用         参数可能被替换到宏体中的多个位置,所以带有副作用的参                函数参数只在传参的时候求值一次,结果更容易控制。
 的参数                数求值可能会产生不可预料的结果。
参数类型          宏的参数与类型无关,只要对参数的操作是合法的,它就可                  函数的参数是与类型有关的,如果参 数的类型不同,就                                                                                                                                           需要不同的函数, 即使他们执行的任务是不同的。
                                                                                                                                       以使用于任何参数类型。
调 试                  宏是不方便调试的                                                                                           函数是可以逐语句调试的                                                    
递归                   宏是不能递归的                                                                                   函数是可以递归的

2.5  #undef:  终结宏

这条指令用于移除一个宏定义。
#undef NAME            //如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

2.6  鸡肋——条件编译(底层对库进行修改使用比较广泛)

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
比如说:
         调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。
如:
#include <stdio.h>
#define max 2
int main()
{
#if max == 1
	printf("hehe\n");  // 不编译
#elif max == 2
	printf("baba\n");  // 编译
#else
	printf("gungun\n");  // 不编译
#endif // 1
	return 0;
}

2.7  文件包含#include

    我们已经知道, #include 指令可以使 另外一个文件 被编译。就像它实际出现于 #include 指令的地方一样。
这种替换的方式很简单: 预处理器先删除这条指令,并用包含文件的内容替换。 这样一个源文件被包含10 次,那就实际被编译10 次。(多次包含很浪费资源)
    我们会注意到:
#include  <stdio.h>   
#include "text.h"       //  自建头文件 

有“”  与  <>  两种,其实是两种查找策略:

  •  “”   :先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头 文件。 如果找不到就提示编译错误。
  • <> :   查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。(库文件自带的安装路径)

这样是不是可以说,对于库文件也可以使用 “” 的形式包含?答案是肯定的,可以,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

2. 71 如何解决头文件多重包含?

解决办法:

  • 高级的: 头文件开头 加上 #pragma once

 #pragma once

  • 自己写: 在头文件开头
#ifndef _text_h_   // 没定义 返回1;否则返回0,结束编译
#define _text_h_

// ....... 各种包含头文件,函数声明
int k(int x, int y);
// .......

#endif // !_text_h_

三. 结语

     本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。

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

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

相关文章

阿里全新推出:微服务突击手册,把所有操作都写出来了

今天给大家带来的这份微服务是由阿里巴巴高级技术专家整理&#xff0c;针对Spring Cloud在国内的使用情况&#xff0c;结合国内上百家企业使用Spring Cloud落地微服务架构时遇到的问题和相应的解决方案结合成了这份电子版教程。&#xff08;文末有免费的获取方式&#xff09; …

火伞云APP盾,您身边的DDoS攻击安全保护专家

近年来全球各地区DDoS攻击的比例和次数在逐年增加&#xff0c;严重影响到网络信息安全。 主要有以下原因&#xff1a; 攻击成本低&#xff0c;攻击无壁垒。进行DDoS攻击成本很低&#xff0c;最低甚至只需要几百元就可以轻松发起一次攻击&#xff0c;然而被攻击的对象可能动辄…

3自由度并联绘图机器人实现写字功能(一)

1. 功能说明 本文示例将实现R305样机3自由度并联绘图机器人写字的功能。 2. 电子硬件 在这个示例中&#xff0c;采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板Bigfish2.1扩展板电池7.4V锂电池 3. 功能…

九种 OOM 常见原因及解决方案(IT枫斗者)

九种 OOM 常见原因及解决方案(IT枫斗者) 什么是OOM&#xff1f; OOM&#xff0c;全称“Out Of Memory”&#xff0c;翻译成中文就是“内存用完了”&#xff0c;来源于java.lang.OutOfMemoryError。看下关于的官方说明&#xff1a;Thrown when the Java Virtual Machine canno…

使用 Amazon SageMaker 构建文本摘要应用

背景介绍 文本摘要&#xff0c;就是对给定的单个或者多个文档进行梗概&#xff0c;即在保证能够反映原文档的重要内容的情况下&#xff0c;尽可能地保持简明扼要。质量良好的文摘能够在信息检索过程中发挥重要的作用&#xff0c;比如利用文摘代替原文档参与索引&#xff0c;可…

数据结构复习题(包含答案)

第一章 概论 一、选择题 1、研究数据结构就是研究&#xff08; D &#xff09;。 A. 数据的逻辑结构 B. 数据的存储结构 C. 数据的逻辑结构和存储结构 D. 数据的逻辑结构、存储结构及其基本操作 2、算法分析的两个主要方面是&#xff08; A …

Multi-modal Alignment using Representation Codebook

Multi-modal Alignment using Representation Codebook 题目Multi-modal Alignment using Representation Codebook译题使用表示子空间的多模态对齐期刊/会议CVPR 摘要&#xff1a;对齐来自不同模态的信号是视觉语言表征学习&#xff08;representation learning&#xff09;…

SpringMVC文件上传、异常处理、拦截器

SpringMVC文件上传、异常处理、拦截器 基本配置准备&#xff1a;maven项目模块 application.xml <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.…

数据库系统-数据物理存储

文章目录 一、DBMS原理1.1 DB物理存储1.1.1 磁盘的结构&特性1.1.2 DBMS数据存储&查询原理记录&#xff1a;磁盘块 1.2 DB文件组织方法1.2.1 无序文件组织1.2.2 有序记录文件1.2.3 散列文件(Hash File)1.2.4 聚簇文件(Clustering File) 1.3 Oracle 物理存储简介 一、DBM…

程序员最常见的谎言

小伙伴们大家好&#xff0c;我是阿秀。 上周看到知乎上有位网友总结了自己的10年程序员生涯中最常说的一些谎言&#xff0c;一共有15条&#xff0c;看完我直呼内行&#xff01;&#xff01; 全中&#xff01;每一枪都中了&#xff01;每一条我都说过。 我基本都说过他说过的那些…

下载VMware安装Ubuntu18.04.6系统

文章目录 前言&#xff1a;1. 下载VMWare与Ubuntu镜像2. 安装VMware3. VMware下安装Ubuntu 前言&#xff1a; 这篇文章是为交叉编译做的铺垫&#xff0c;本文内容比较简单&#xff0c;按步骤操作即可。 1. 下载VMWare与Ubuntu镜像 为了节约大家时间&#xff0c;省的各种找&am…

【Unity VR开发】结合VRTK4.0:摄像机碰撞变黑

语录&#xff1a; 人是要长大的&#xff0c;有天你也会推着婴儿车幸福地在街上行走&#xff0c;而曾经的喜欢&#xff0c;不管曾经怎样&#xff0c;都会幻化成风&#xff0c;消失在时光的隧道。所以向前走&#xff0c;向前走&#xff0c;无须回头。 前言&#xff1a; 往往我们在…

基于html+css的图片展示12

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

新品发布 | 智安网络【零信任SDP访问控制系统】正式上线!

近日&#xff0c;根据《2022年云办公行业研究报告》显示&#xff0c;2021-2023年&#xff0c;中国协同办公行业保持每年10%以上的增长率&#xff0c;远程办公人员的数量在过去十年中增长了115%&#xff0c;互联网时代已迎来远程办公需求大潮。 风口之下&#xff0c;员工对企业…

Go语言基础——通过获取网站API的cUrl,生成可直接执行的request代码(附:详细实战案例和源码)

作者&#xff1a;非妃是公主 专栏&#xff1a;《Golang》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录 一、cUrl是什么&#xff1f;二、cUrl如何获取…

OpenAI-ChatGPT最新官方接口《从0到1生产最佳实例》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(十一)(附源码)

Production Best Practices 生产最佳实例 前言Introduction 导言Setting up your organization 设置您的组织Managing billing limits 管理计费限额API keys API密钥Staging accounts 演示账户 Building your prototype 构建您的原型Additional tips 其它技巧 Techniques for i…

【Java 数据结构】队列的实现及相关OJ题

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

图的搜索算法---8.2 ZOJ1002-Fire Net--合理布置碉堡

目录 问题&#xff1a; 分析&#xff1a; 主要的算法代码&#xff1a; 完整代码&#xff1a; 出问题的代码&#xff1a; 原因&#xff1a; 正确代码&#xff1a; 代码分析&#xff1a; 算法函数讲解&#xff1a; CanPut函数 solve函数 运行结果&#xff1a; 问题&am…

勇创世界一流!移动云为我国数字经济发展提供有力支撑

今年2月&#xff0c;中共中央、国务院印发了《数字中国建设整体布局规划》&#xff0c;通过顶层设计及布局&#xff0c;擘画了我国数字经济发展蓝图。近日在国新办举行的第六届数字中国建设峰会新闻发布会上&#xff0c;相关负责人也对我国数字经济现阶段取得的成绩进行了总结&…

IPWorks VoIP 2022 Crack

网络电话组件 IPWorks VoIP 提供 SIP 和 IVR 组件&#xff0c;旨在促进 CTI 应用程序中的常见 VoIP 操作。快速集成功能以建立拨出电话、接听来电以及根据您的自定义 IVR 菜单路由呼叫。还支持其他 SIP 功能&#xff0c;例如文本到语音、播放预先录制的消息、通话录音和电话会议…