#define、const和enum三种常量表示方式

@YangYang48

引言

说起常量,最直观的常量就是用#define、const和enum方式。

Qustion

那么任何情况下这三种常量的表示都可以使用吗?
如果不能同时使用,那么分别的适用场合又是哪一些呢?

我们带着上述的疑问开始对这三个系统的分析,那么开始吧。

#define

定义

C/C++
语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。

说的感觉有点云里雾里,通俗的来说明就是我用一个字符或者字符串代表替换文本。这个替换文本包括整形,字符串,表达式等。具体的来说宏定义还分为有参和无参的两种形式,这边对有参不展开说明。喜欢专研的小伙伴具体可以看宏定义有参

举例说明

这里其名称(宏名)一般大写,而且不能有空格。

#define YEAR 2020
#define YY "2020"

具体实现可以看下面的代码

//demo1
#include "stdafx.h"
#define YEAR 2020			//宏定义数字
#define YY "2020"			//宏定义字符
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	cout << YEAR << endl;	//处理前数字常量输出
	cout << YY << endl;		//处理前字符串常量输出
	//进行处理
	int num = YEAR + 1;
	char s[20];
	strcpy_s(s,5, YY);
	cout << num << endl;	//这个数字常量可以直接赋值使用
	cout << s << endl;		//这个字符串常量可以通过拷贝函数使用	
	return 0;
}

这边还有一种表达常量的方法,就是表达式,形式如下所示

//demo2
#include "stdafx.h"
#define YEAR 15+5 				//很显然这个值也是20
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	cout << YEAR << endl;		//这个值是20
	//进行处理
	int num = YEAR * YEAR;		//这个值会等于400?
	cout << num << endl;
	return 0;
}

结果如下显示:
在这里插入图片描述
这是由于这个宏定义的机制所造成的的,它是一种替换,而不是直接的赋值
YEAR * YRAE = 15+5*15+5 = 95而不是YEAR * YEAR = (15+5) * (15+5) = 400

这边会有一个疑问?
那么用#define能不能变成类型名呢?
其实是可以的

//demo3
#include "stdafx.h"
#define INTEGER int
typedef int INT;
#define INTEGERP int*
typedef int* INTP;
#include <iostream>
#include <assert.h>
using namespace std;
int aa = sizeof(INTEGER);
int bb = sizeof(INT);
int main()
{
	cout << aa << " " << bb << endl;
	INTEGER a = 1;
	INT b = 2;
	assert(a-b <= 0);
	cout << a << " " << b << endl;
    //进行处理
	INTEGERP p1 = &a;
	INTP p2 = &b;
	cout << *p1 << " " << *p2 << endl;
	return 0;
}

上述的两种方式都可以变成int类型的两类和指向int类型的指针,但是两者有区别。#define是在预处理阶段就已经替换,而typedef更像是int类型的一个别名,发生在编译运行阶段。

总结:#define有三种方式表达常量,有常量字符、常量数字和常量的表达式(不推荐使用表达式)。

const

定义

常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的

核心关键词是用于常类型的变量或对象,举例如下。

const int Year = 2020;
int Year_1 = 2020;
const int* p1 = Year_1;
int const *p2 = Year_1;
int* const p3 = Year_1;
const int* const p4 = Year_1;

const修饰部分原则

1.看左侧的最近部分
2.如果左侧没有,则看右侧

//demo4
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
	int Year = 2020;
	const int* p1 = &Year;
	int const *p2 = &Year;				//p1和p2是同种类型的,指向内容不能变
	int* const p3 = &Year;				//p3指针所指向的不能变
	const int* const p4 = &Year;		//p4指针所指向的和指向内容都不能变	
	int YY = 2021;
	p1 = &YY;
	p2 = &YY;
	//p3 = &YY;
	//p4 = &YY;
	cout << *p1 << endl;
	cout << *p2 << endl;
	cout << *p3 << endl;
	cout << *p4 << endl;
	//*p2 = *p2 + 1;
	*p3 = *p3 + 1;
	//cout << *p2 << endl;
	cout << *p3 << endl;
	return 0;
}

const不仅仅是int类型可以表示的,字符串类型同样可以。
关于const与字符串指针的关系,代码如下:

//demo5
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
	char str[] = "helloworld";
	char const *p1 = "helloworld1";			//const char*
	//char *const p2 = "helloworld2";			//p2不能改变指向,如果变了内容那么原指向找不到了
	char *const p2 = str;
	char const *const p3 = "helloworld3";	//const char* const
	p1 = str;
	//p2 = str;								//p2不可改
	//p3 = str;								//p3不可改
	cout << p1 << endl;
	cout << *p1 << endl;
	cout << *p2 << endl;
	cout << p2 << endl;
	cout << p3 << endl;
	for (int i = 0; i < 10; i++)
	{
		str[i] += 1;
		//p1[i] += 1;
		p2[i] += 1;
		//p3[i] += 1;
	}
	cout << str << endl;
	cout << p2 << endl;
	return 0;
}

那么上述知道了#define和const之后,发现似乎有点类似又有所区别,这边将weixin_41521306的整理出来的异同点展开描述。

异同点 #define const
作用阶段 预处理阶段 编译、运行
作用的方式 简单的字符替换,没有类型检查 对应数据类型,进行类型检查
存储方式 内存中有若干个备份,占用代码段空间 只有一份备份,占用数据段空间
代码调试 不能调试,在预编译阶段已替换掉 可以进行调试的
再定义 #undef取消某个符号的定义,再重新定义 不能重定义
特殊功能 防止头文件重复引用 不能防止头文件重复引用
用于类 可用于全局变量 用于类成员变量的定义,且定义后不可改

在这里插入图片描述

因此,总结了上述的异同点可知,我们在c++中尽量使用const定义变量,方便于开发人员排查错误。

enum

定义

枚举类型(enumeration)是 C++ 中的一种派生数据类型,它是由用户定义的若干枚举常量的集合

enum不仅能够创建符号常量,还能创建新的数据类型。

enum week {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; // 定义枚举类型week,默认从0开始依次加1

对应关系如下表所述:

枚举型变量 对应整数值
sun 0
Mon 1
Tue 2
Wed 3
Thu 4
Fri 5
Sat 6
enum week1 {Sun=7, Mon=1, Tue, Wed, Thu, Fri, Sat}; // 定义枚举类型week,默认从0开始依次加1

对应关系如下表所述:

枚举型变量 对应整数值
sun 7
Mon 1
Tue 2
Wed 3
Thu 4
Fri 5
Sat 6

枚举常量只能以标识符形式表示,而不能是整型、字符型等文字常量。

//错误示例1
enum letter_set {'a','b','c','d','e'}; //枚举常量不能是字符常量

错误原因:字符本身就有对应的ASCII码值,所以再将字符对应整数就会出现问题,不成立

//错误示例2
enum year_set{2020,2021,2022,2023,2024,2025}; //枚举常量不能是整型常量

错误原因:这个本身就是数字,已经有相应的二进制数表示了,所以也不能对应其他整数,不成立

综上,举例说明枚举类型的常量

//枚举值不可以做左值,枚举变量可以赋值给非枚举变量
#include "stdafx.h"
#include <iostream>
using namespace std;
enum week 
{
	Sun = 7,
	Mon = 1,
	Tue,
	Wed,
	Thu,
	Fri,
	Sat
};
int main()
{
	week wk;
	int a;
	wk = Mon;			//Mon=1
	wk = Tue;			//Tue=2
	//wk = 1;			//不能直接将整形类型赋值
	wk = (week)(1);		//强制转化类型
	cout << wk << endl;
	a = Mon;
	cout << a << endl;	//可以直接赋值给整形类型
	return 0;
}

总结

#define注重预处理的替换,const倾向于常类型的变量或对象,enum更偏向于一种自定义的数据类型,建议多使用const作为常量表达方式,原因是适用范围广且容易排查错误。

参考

1.菜鸟加贝的爬升,https://www.cnblogs.com/jiabei521/p/3335676.html
2.Shmilxu的博客,https://www.cnblogs.com/shmilxu/p/4837373.html
3.Oragen,https://blog.csdn.net/magic_world_wow/article/details/80733495
4.葫芦娃的后桌,https://www.cnblogs.com/happying30/p/9350712.html
5.京鸿智武,https://zhuanlan.zhihu.com/p/46602697
6.weixin_41521306,https://blog.csdn.net/weixin_41521306/article/details/88574016
7.学习笔记666,https://blog.csdn.net/github_26672553/article/details/82957003
8.猿问,http://www.imooc.com/wenda/detail/522431


版权声明:本文为yangju147532896原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>