【016】C++预处理详解(内存分区、变量的存储、头文件、宏等)

news2024/11/12 18:02:27

C++内存分区和变量存储

  • 引言
  • 一、内存分区
  • 二、变量的存储
    • 2.1、普通局部变量
    • 2.2、普通全局变量
    • 2.3、静态局部变量
    • 2.4、静态全局变量
  • 三、全局函数和静态函数
    • 3.1、全局函数
    • 3.2、静态函数(static修饰的函数)
  • 四、头文件包含
  • 五、#define宏
    • 5.1、不带参数的宏
    • 5.2、带参数的宏
    • 5.3、宏函数和普通函数的区别
  • 总结

引言


💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
👉
🎖️ CSDN实力新星,社区专家博主
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【015】C++的函数详解

一、内存分区

可执行文件从运行到结束的整个动态过程称为进程。
在这里插入图片描述

  • 栈区:可读可写,存储局部变量,函数形参、返回值等。
  • 堆区:可读可写,使用malloc、calloc、realloc动态申请。
  • 全局区:可读可写,保存普通全局变量、静态全局变量、静态局部变量。
  • 常量区:只读,保存数值常量、字符常量、字符串常量、符号常量。
  • 代码区:只读,程序的二进制指令。

二、变量的存储

2.1、普通局部变量

定义:在{} 里面定义的普通变量就是普通局部变量。

int main()
{
	int num=0;//局部变量
	{
		int num2=0;//局部变量
		
	}
	return 0;
}

作用范围:所在的{}复合语句之间有效。
生命周期:所在的{}复合语句之间有效。
存储区域:栈区。
注意事项:

  • 普通局部变量不初始化,内容是不确定的。
  • 普通局部变量同名情况下,采用就近原则。
int main()
{
	int num=0;//局部变量
	{
		int num=10;//局部变量
		cout<<"num = "<<num<<endl;
	}
	cout<<"num = "<<num<<endl;
	return 0;
}

输出:

10
0

2.2、普通全局变量

定义:在函数外定义的普通变量就是普通全局变量。

int num;
int main()
{
	cout<<num<<endl;
	return 0;
}

作用范围:当前源文件以及其他源文件有效。
生命周期:整个进程。
存储区域:全局区。
注意事项:

  • 普通全局变量不初始化,内容是0。
  • 普通局部变量和普通全局变量同名情况下,优先选择局部变量。
int num;
int main()
{
	int num=10;
	cout<<num<<endl;
	cout<<::num<<endl;// C++支持通过作用域方式访问全局变量,c语言不支持
	return 0;
}

输出:

0
10
  • 其他源文件使用全局变量必须对全局变量进行extern声明。extern声明外部可用,该变量或函数来自其他源文件。
// main.cpp
int num;
int main()
{
	int num=10;
	cout<<num<<endl;
	cout<<::num<<endl;// C++支持通过作用域方式访问全局变量,c语言不支持
	return 0;
}
// test.cpp
extern int num;
int test()
{
	cout<<num<<endl;
	return 0;
}

2.3、静态局部变量

定义:在{} 里面叫static定义的普通变量就是静态局部变量。

void test()
{
	static int data = 10;
}

作用范围:所在的{}复合语句之间有效。
生命周期:整个进程有效。
存储区域:全局区。
注意事项:

  • 静态局部变量不初始化时,内容默认为0。
  • 静态局部变量整个进程都存在,第一次定义有效。
#include <iostream>
using namespace std;

void test()
{
	int data=10;
	static int data=10;
	data2++;
	cout<<"data: "<<data<<endl;
	cout<<"data2: "<<data2<<endl;
}

int main()
{
	test();
	test();
	test();
	test();
	test();
	return 0;
}

输出:

data: 10
data2: 11

data: 10
data2: 12

data: 10
data2: 13

data: 10
data2: 14

data: 10
data2: 15

2.4、静态全局变量

定义:在函数外定义的使用static修饰的变量就是静态全局变量。

static int num;
int main()
{
	cout<<num<<endl;
	return 0;
}

作用范围:只能在当前源文件使用,不能在其他源文件使用。
生命周期:整个进程。
存储区域:全局区。
注意事项:

  • 静态全局变量不初始化,内容为0。
  • 静态全局变量只能在当前源文件使用。

三、全局函数和静态函数

3.1、全局函数

函数默认都是全局函数。全局函数在当前源文件以及其他源文件都可以使用。如果其他源文件使用需要extern对全局函数进行声明。

// main.cpp
int num;
extern test();//全局函数的声明
int main()
{
	int num=10;
	cout<<num<<endl;
	cout<<::num<<endl;// C++支持通过作用域方式访问全局变量,c语言不支持
	test();
	return 0;
}
// test.cpp
extern int num;
int test()
{
	cout<<num<<endl;
	return 0;
}

3.2、静态函数(static修饰的函数)

静态函数只能在当前源文件使用。

// main.cpp
int num;
static int test();//函数的声明
int main()
{
	int num=10;
	cout<<num<<endl;
	cout<<::num<<endl;// C++支持通过作用域方式访问全局变量,c语言不支持
	test();
	return 0;
}

static int test()
{
	cout<<num<<endl;
	return 0;
}

四、头文件包含

在预处理结果将头文件的内容原封不动的包含在目的文件中。

  • <>从系统指定目录寻找头文件。
  • ""先从当前目录寻找头文件,如果找不到,再从系统指定目录寻找头文件。
    在这里插入图片描述

五、#define宏

编译的四个阶段:预处理、编译、汇编、链接。
使用关键字define定义的称为宏。

#define PI 3.1415926 //宏定义

在预处理时,使用3.1415926替换PI出现的位置,称为宏展开。
注意:

  • 不要在宏后面添加分号。
  • 宏尽量大写,和变量区分开。

5.1、不带参数的宏

#define PI 3.1415926 //宏定义
#define STRING	"hello cpp"
#define INT32	32

宏的作用范围:从定义处开始到当前文件结束有效。#undef可以结束宏的作用域。

#define PI 3.1415926 //宏定义
// ....
#undef PI	//结束宏的作用域
// ...

宏没有作用域的限制,只在当前源文件有效。

5.2、带参数的宏

#define MUL(a,b)	a*b

cout<<MUL(10,20)<<endl;
// 宏展开后:cout<<10*20<<endl;

(1)宏的参数不能有类型。
(2)宏不能保证参数的完整性。

#define MUL(a,b)	a*b

cout<<MUL(10+10,20)<<endl;
// 宏展开后:cout<<10+10*20<<endl;

可以使用()的形式让带参数的宏具备完整性。

#define MUL(a,b)	(a)*(b)

cout<<MUL(10+10,20)<<endl;
// 宏展开后:cout<<(10+10)*20<<endl;

(3)宏不能作为结构体、类的成员。

5.3、宏函数和普通函数的区别

  1. 定义方式不同:宏定义是通过#define关键字定义的,而普通函数则需要先声明再实现。
  2. 编译时机不同:宏函数是在编译时展开的,而普通函数则是在运行时执行的。
  3. 参数传递方式不同:宏函数可以接受任意类型的参数,并且不需要进行类型检查。相比之下,普通函数对于每个参数都需要进行类型检查。
  4. 返回值处理方式不同:宏函数不能像普通函数一样返回结果。相反,它会直接替换为预处理器指令。
  5. 带参数宏调用多少次就展开多少次,执行代码的时候没有函数调用的过程,不需要压栈出栈。所以带参数宏是浪费空间来节省时间。
  6. 带参数函数,代码只有一份,存储在代码段,调用的时候去代码段取指令,调用的时候要压栈出栈,属于浪费时间来节省空间。
  7. 函数有作用域限制,可以作为类的成员。而宏是没有作用域限制的,不能作为类的成员。

总结

C++预处理器是一个非常重要的编译阶段,它在源代码被编译之前对源代码进行一些操作。以下是一些常见的C++预处理指令和其作用:

  1. #define:定义宏常量或宏函数,可以提高代码的可读性和可维护性。
  2. #ifdef / #ifndef / #endif:条件编译指令,用于根据条件选择是否编译某段代码。
  3. #include:包含头文件,将其他源代码文件中的定义导入到当前文件中以供使用。
  4. #pragma:通用预处理命令,用于指示编译器执行特定的动作或更改默认行为。
  5. #error:产生错误消息并停止编译过程。
  6. #undef:取消已定义的宏。

除了上述常见预处理指令外,C++还有一些其他的预处理功能,例如__FILE__、__LINE__等预定义标识符。这些标识符可以在程序运行时提供有关程序状态和调试信息。

总体来说,C++预处理器为程序员提供了很多便利,在正确使用的情况下能够有效地提高开发效率和代码质量。但需要注意,在不适当地使用它们的情况下,会带来潜在的风险和问题。

在这里插入图片描述

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

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

相关文章

chatgpt赋能python:Python中的不确定尾数问题

Python中的不确定尾数问题 Python作为一种高级编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等众多领域。然而&#xff0c;Python在处理浮点数时会出现一些不确定尾数的问题&#xff0c;给程序员和数据分析员带来不少麻烦。本篇文章将介绍Python中不确定尾数的…

抖音seo开源源码,抖音优化系统定制方案

抖音作为目前最火热的短视频平台之一&#xff0c;其在移动互联网领域的影响越来越大。然而&#xff0c;一款成功的产品未必仅仅靠着其自身的功能和品质就能获得市场的认可&#xff0c;还需要通过优化SEO来实现更好的曝光率。下面&#xff0c;本文将介绍如何优化抖音SEO源码开发…

16个好用到爆的Python实用技巧!

Python 是一门用途广泛的编程语言&#xff0c;它具有大量的库和框架。有一些鲜为人知的 Python 编码技巧和库可以让你作为开发人员的工作更为轻松&#xff0c;编写代码更高效。 本文将探讨一些鲜为人知的 Python 技巧&#xff0c;这些技巧非常有用&#xff0c;但并不广为人知。…

领域驱动模型VO,BO,PO,DO,DTO概念介绍和区别

先来一张图&#xff0c;有一个直观地感受&#xff1a; 概念介绍 VO&#xff08;View Object&#xff09;视图对象 用于展示层&#xff08;和控制层Controller共同属于表现层&#xff09;&#xff0c;它的作用是把某个指定页面&#xff08;或组件&#xff09;的所有数据封装起来…

机器学习算法

机器学习擅长的任务: ● 回归&#xff08;regression&#xff09; ● 分类&#xff08;classification&#xff09; ● 聚类&#xff08;clustering&#xff09; 1.回归&#xff08;regression&#xff09; 回归是处理连续数据时使用的方法&#xff0c;如时间序列数据。 …

vue使用obs华为云上传图片或者视频

可惜只支持web和h5 api链接 引入&#xff0c;位置自己放&#xff0c;我放了两个其实一个就可以 import ObsClient from "./../common/esdk-obs-browserjs-without-polyfill.3.23.5.min.js";使用 Bucket桶名&#xff1b;Key可以理解为参数&#xff1b;SourceFile文…

香豆素荧光标记652966-03-5,ATTO425 acid,ATTO 425 羧酸,进行简析说明

中文名称&#xff1a;ATTO 425 羧酸 英文名称&#xff1a;ATTO425 COOH&#xff0c;ATTO-425 carboxylic acid 规格标准&#xff1a;10mg&#xff0c;25mg&#xff0c;50mg CAS&#xff1a;652966-03-5 分子式&#xff1a;C22H27NO6 分子量&#xff1a;401.46结构式&#xff1a…

90.qt qml-Table表格组件(支持表头表尾固定/自定义颜色/自定义操作按钮/插入排序)

众所周知,qml table在目前版本还很废,qt5的table完全就没法用,在之前章节就写过: 88.qt qml-TableView学习(一)_诺谦的博客-CSDN博客 所以本章便参考VUE-Element的Table外观组件实现一个可排序可操作的Table组件. 1.组件介绍 GIF如下所示: 排序支持数字和字符串排序。 …

Mysql5.7.41windows安装

Mysql5.7.41windows安装 Mysql5.7.41windows安装Mysql5.7.41官方下载mysql安装 配置PATH路径&#xff0c;任意位置打开cmd都可以连接Mysql环境验证&#xff0c;并登录友情链接 Mysql5.7.41windows安装 本文主要完成windows从下载到安装的安装文档撰写。 Mysql5.7.41官方下载 …

html实现会拐弯的时间线,jquery实现会拐弯的时间线,css实现会拐弯的时间线

前言 jquery html css实现一个会拐弯的时间线 基于此网址整改&#xff0c;参考&#xff1a;https://www.jq22.com/webqd5873 效果 实现 基于jQuery&#xff0c;需要引入jQuery.js&#xff0c;没有必要使用太高版本&#xff0c;够用就行 jquery下载&#xff1a;https://www…

SadTalker 学习笔记

SadTalker: Learning Realistic 3D Motion Coefficients for Stylized Audio-Driven Single Image Talking Face Animation 摘要 Generating talking head videos through a face image and a piece ofspeech audio still contains many challenges. i.e., unnatural head mo…

前端页面调用EXE应用程序

文章目录 1️⃣ 操作步骤1.1 操作注册表1.1.1 创建 xcLeigh.reg 注册表文件1.1.2 安装 xcLeigh.reg 注册表文件1.1.3 放入EXE文件 1.2 界面代码1.3 运行效果 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details…

大专毕业,从6个月开发转入测试岗位的一些感悟 —— 写在测试岗位3年之际

时光飞逝&#xff0c;我从前端开发岗位转入测试岗位已经三年了&#xff0c;这期间从迷茫到熟悉&#xff0c;到强化&#xff0c;到熟练&#xff0c;到总结&#xff0c;感受还是很深的&#xff01; 三年前的某一个晚上&#xff0c;我正准备下班回家&#xff0c;我们的项目经理把…

嵌入式Linux中的 gpio、gpiod基本分析

GPIO 应该是每个嵌入式设备都避免不了的。最近在做项目的时候&#xff0c;也遇到这方面的问题&#xff0c;所以简单总结一下。 现在内核里面多了 gpiod 的来控制 gpio 口&#xff0c;相对于原来的形式&#xff0c;使用 gpiod 的好处是我们申请后不进行 free 也没有什么问题。但…

Seata分布式事务AT、TCC、SAGA、XA模式

Seata是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式&#xff0c;为用户打造一站式的分布式解决方案。 AT模式 &#x1f36e;实现原理 阿里SEATA独有模式&#xff0c;通过生成反向SQ…

STM32读取24位模数转换(24bit ADC)芯片ADS1231数据

STM32读取24位模数转换&#xff08;24bit ADC&#xff09;芯片ADS1231数据 ADS1231是一款TI公司出品的24位ADC芯片&#xff0c;常用于与称重传感器配合实现体重计的应用。这里介绍STM32读取ADS1231的电路和代码实现。ADS1231的特点为通过硬件管脚可控制两种采样速率&#xff0…

日期与字符串相互转化(自定义日期工具类总结,Hutool工具类使用)

一、将日期格式化成字符串输出&#xff08;Date转String&#xff09; Java旧的时间API饱受诟病&#xff0c;Java8以后提供了新的时间API&#xff0c;在java.time包下。 //获取当前时间LocalDateTime dateLocalDateTime.now();//创建日期时间对象格式化器&#xff0c;日期格式类…

Hadoop学习---11、HA高可用

1、Hadoop HA高可用 1.1 HA概述 1、所谓HA&#xff08;High Availablity&#xff09;&#xff0c;即高可用&#xff08;7 * 24小时不中断服务&#xff09;。 2、实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制&#xff1a;HDFS的HA和YARN的HA。 …

数字化转型,低代码开发真的靠谱?

关于数字化转型&#xff0c;有这么一种定义&#xff0c;即利用数字化技术和能力来驱动企业商业模式创新和商业生态系统重构的一种途径与方法。通俗点说&#xff0c;数字化的核心和目的就是通过数字化技术&#xff0c;实现业务的转型、创新和增长&#xff0c;提供新的营收点与价…

超详细,性能测试三大模式详解,资深测试老鸟一文道破...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在性能测试工作中…