const和#define使用及区别

1、编译处理阶段不同:define是在预处理阶段进行宏展开,const是在编译运行阶段。
2、类型和安全检查不同:const常量有具体的类型,在编译阶段会执行类型检查,而define没有。
3、存储方式不同:const常量会进行内存分配(C++中,对于简单类型的临时常量会保存在符号表里面进行替换,而不会分配内存),而define仅仅是展开,不会分配内存。
4、有些调试工具可以对const进行调试,但是不能对宏定义进行调试。

一、const使用
1、C默认const是外部连接的,C++默认const是内部连接的。
2、const修饰变量的值,并非不可改变。比如强转。
3、const限定词作用类型:
      1)简单常量(C++中,称为值替代,因为不会分配内存)
            const int c = 100;
     2)指向const的指针(p is a pointer to const int)
           const int *p
     3)const指针(p is a const pointer to int)
            int * const p
     4)函数形参(意义不大,用于指向const指针时OK)
           int func(const int a)
     5)const返回值
          const int func()
    6)const类成员变量
          只在对象存在的生命周期内是不可变的,所以不同的对象有可能是不同的。
          并且需要通过构造函数初始化,或声明为static类型。
          如果需要编译期常量,保证所有的对象一致,可以定义为枚举类型,或者static const类型。
    7)const对象和const成员函数
          int func() const;
          const对象保证类公有成员变量不会被修改。
          const成员函数保证不会修改类成员变量。任何不修改成员数据的函数应该声明为const函数。
          但是在const成员函数内,使用mutable修饰的成员变量,是可以被修改。
          只有const成员函数才能被const对象调用。

二、#define使用

    1、定义常量:
           #define <宏名>  <字符串>

#define PI 3.1415926

    2、函数宏,代替模板和内联函数
            #define <宏名> ( <参数表>) <宏体>  

#define SWAP(a,b) do\
{\
decltype(a) temp = a;\
a = b;\
b = temp;\
}while(0)

[1]函数定义块如果需要换行,那么换行是结尾需加反斜杠

[2]可以利用decltype来获得函数参数的类型,方便函数中内容的执行

[3]利用do while(0)可以使函数中的变量变成局部变量,也可使用{},且使语法清晰减少出错

[4]有时可用这种宏的方式可以代替c++的模板,执行效率要比模板快

[5]因为是文本替换,所以尽量不要把分号写进去,在调用的时候补充分号

3、预编译逻辑判断

可以利用#if #elif #else #endif来进行编译时的逻辑处理。

[1]可以使用与或非逻辑判断

[2]一旦代码开始编译函数后,#define 和 #undef将被无效化,要在文件开头处使用#define 或 #undef

[3]可利用这个防止头文件被重复加载

#ifndef DEMO_H
#define DEMO_H

#include <iostream>

using namespace std;
 
#define DEBUG
 
void MyLog(string logger)
{
#if defined(DEBUG)
    cout << "MyLog = " << logger << endl;
#endif
}
 
void test()
{
#if defined(WIN32)
    cout<<"this device is WIN32" << endl;
#endif 
 
#if !defined(WIN32)
    cout<<"this device is not WIN32" << endl;
#endif 
 
#if defined(WIN32)&&defined(LINUX)
    cout <<"win32 and linux" << endl;
#endif
    MyLog("1");
#undef DEBUG 
    MyLog("2");
}

#enif

宏详解:

一个标识符被宏定义后,该标识符便是一个宏名。在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换

预处理器实现以下的功能:
(1) 文件包含
可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
(2) 条件编译
预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。
(3) 宏展开
预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。
经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。

三、函数式宏:

包括函数式宏)  没有返回值的概念,函数才有返回值的概念

函数才有返回值的概念,因为调用函数时有一个切换并保护现场的过程,所以切换回来(到调用者)时就需要通过返回值将函数的结果传送回来。

宏(包括函数式宏)  没有返回值的概念,因为它只是在源代码文件(级别)上的文本替换(即修改些源代码),没有一个切换并保护现场的过程,所以不需要也不存在一个通过返回值将其的结果传送回来的过程。还有,宏函数有个结果值(最后一个表达式),宏函数隐式地指名了其“返回值”与“返回类型”。

#define A(a,b,c) ({a=1;b+=1;c=3;a+b+c;})
#include <stdio.h>
int main()
{
int a;
int b=1;
int c;
int d =A(a,b,c); // 这种宏给变量赋值的写法在vs2015中是不支持的
printf("%d,%d,%d,%d\n",a,b,c,d);
return 0;
}

运行结果:
1,2,3,6

 其中,宏函数 A(a,b,c)有一个结果值(但不叫返回值),即最后一个式子的返回值作为宏函数的返回值。宏函数 A(a,b,c)所代表的整体表达式({a=1;b+=1;c=3;a+b+c;})或说{a=1;b+=1;c=3;a+b+c;}有一个结果值,即最后一个式子a+b+c的结果值作为宏函数所代表的整体表达式的结果值。

1、#define xxx() {} ,是标准C支持的,
也是GCC新增的功能(微软vS不支持),主要为了防止宏展开出现问题,默认展开时是要加上一个;的(即{;}),(否则)容易出问题。

2、#define xxx() ({})   // ()是为了保证宏替换的计算优先级,{}使函数中的变量变成局部变量,且使语法清晰减少出错。

3、如果是带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号

      例:#define (x)  ((x)*(x))

宏定义优点:

1、 方便程序的修改

2、提高程序的运行效率(函数宏优点)
 

 


参考:https://blog.csdn.net/Mountainest/article/details/83691947

           https://blog.csdn.net/haiross/article/details/46470533

           https://www.xuebuyuan.com/2171142.html

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大锅菜~

谢谢鼓励~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值