defines:C++知识进阶之#defines使用优化

在介绍#defines使用优化之前,要首先简单介绍一下编译原理:
比如以C语言为例:

1.预处理阶段
工作内容:a.宏替换;b.头文件展开;c.去注释;d.条件编译
语言转换:C语言 ---------> C语言

**2.编译阶段 **
工作内容:检查语法错误
语言转换:C语言 ---------> 汇编语言

3.汇编
语言转换:汇编语言 ---------> 二进制

4.链接

以上只是简单介绍了一下编译大概过程,详细工作原理还要去查找资料,这里不做过多说明。

#define 宏,它在C语言中就已经存在,C++语言中也延用过来,接下来简单介绍一下他的使用方法和具体的优化。

1.定义:#define 宏名字 替换对象 (值) (替换对象可为空,比如定义一个头文件)

2.宏可以进行函数替换,常量替换,函数替换时可以不带参数类型
特别说明:宏参数需要加括号;宏替换的整体内容需要加括号 ;宏函数中不可以出现递归

#ifndef:指宏没有被定义则执行下面的语句,否则不执行 和 #endif 配套使用
移除宏:
#undef:作用于它被定义后的全部位置,定义之前不作用;如果要重定义宏,需要先移除宏,然后再重定义宏

宏函数和常规函数的区别:
1.宏函数的优点:
a.宏函数比常规函数在程序的规模和运行速度更胜一筹;
b.宏函数的参数不用定义类型,更类似于C++的模板函数,一份代码可以解决多种类型数据的运算;
(我们知道C++里面有模板,我们可以使用模板替换,但是C语言没有模板,所以在C语言中宏函数的概念类似于C++的模板函数)
2.宏函数的缺点:
a.宏函数使代码文本增大,调用也增大;
b.宏函数与类型无关;
c.宏参数的安全性很弱;

宏还有很多定义的方式,比如条件编译里面的宏,#if … #elif … #endif 等,这里不再介绍,如果感兴趣可以研究下C语言中宏的使用。

宏的缺点:
1.定义宏常量后,我们通过编译原理知道,在预处理的时候宏会进行宏替换,如果在编译阶段出现宏常量问题,将宏常量替换成了一个真正的值,比如定义了一个宏常量为20,编译时出问题了,错误会告诉我们是20出问题了,但是不会告诉你是哪个宏出问题了,那么如果我们项目很大的话,这个问题查起来就非常麻烦了。
2.定义宏函数,对于宏的参数安全处理非常麻烦,要加各种括号还不能保证其安全性;
3.宏没有作用域的概念,封装性太弱,不存在private 宏的概念。

C++宏的优化:
1.对于单纯的常量,我们最好使用const 或者 enum 替换掉宏常量;
2.对于形似函数的宏,我们最好使用 inline函数来替换 宏函数;

优化分析:

const替换宏常量:
分为两种情况:
1.类外定义,通常定义式放在头文件内;
特殊情况:如果是定义常量指针的话,通常 const 要写两次


2.类内定义
特殊情况:静态常亮声明的时候,对于(ints, chars, bools)这种类型定义的变量,直接使用声明式赋值,不用再额外在.cpp文件中去定义,以下是头文件中的声明;


以下是.cpp文件中的定义:

但是!!以上情况在某些老的编译器中不支持,不允许static 成员在声明的时候获取初始值,这种情况下,那么我们也需要将初始值放在定义式里面去;(以上我的vs版本是2017版本的,所以是可以支持的)

但是如果在老的编译器中,我们需要声明一个有效长度的数组,但是我们又不能在声明式里面给该常量去赋初始值怎么办?enum hack 枚举 可以帮助我们解决这个问题。


这里有个特别的知识点,注意变量的类型


同时enum 可以确保在不同的编译器(不管好坏)里面,防止不够优秀的编译器导致多余的内存分配。
enum hack是模板元的一想基础技术。

template inline 函数替换宏函数:
宏函数的不安全性,比如:


优化成template inline 函数:


同时弥补了宏函数不能封装的缺点,而且可以获得宏带来的效率以及一般函数的所有可预料行为和类型的安全性。

宏的话外题补充:
细心的人应该会发现,当我们用vs创建一个类的时候,我们的.h头文件 最上面会默认给一个 “ # pragma once ”,这个是干嘛的呢?这个和我们下面这个定义方式的目的是一样的,主要是为了避免同一个头文件被包含(include)多次。但是二者也有一些细微的差别,具体可以根据个人情况去查阅资料,这里不具体介绍。

相关推荐

相关文章