C/C++:#define 与 typedef、const 的使用区别


#define 的用法

#define为宏定义语句,通常用它来定义常量,以及用它来实现宏。它本身并不在编译过程进行,而是在这之前的 预处理过程 中已经完成了,但也因此难以发现潜在的错误以及其他代码维护问题。

#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。

该命令有两种格式:

  • 一种是简单的宏定义
  • 一种是带参数的宏定义

(1)简单的宏定义

#define <宏名> <字符串>

例:

#define PI 3.1415926

(2)带参数的宏定义

#define <宏名> (<参数表>) <宏体>

例:

#define A(x) x

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

define中的三个特殊符号:#,##,#@

#define Conn(x,y) x##y
#define ToString(x) #x
#define ToChar(x) #@x
  1. x##y表示什么?表示x连接y,举例说:
int n = Conn(123,456);				// 结果就是 n=123456;
char* str = Conn("asdf", "adf");	// 结果就是 str = "asdfadf";
  1. #x表示什么?表示给x加双引号,举例说:
char* str = ToString(123132);	// 就成了str="123132";

标准用法只有以上两种!

  1. 再来看#@x,其实就是给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);		// 结果就是 a='1';

#@x的存在,在不同编译器上,结果不同。反正gcc环境下不能运行通过,直接报错。(VS2017 好像能编译通过)


typedef 的用法

typdef常用来定义一个标识符以及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间。

例如,C 语言在 C99 之前并未提供布尔类型,但我们可以使用 typedef 关键字来定义一个简单的布尔类型,如下面的代码所示:

typedef int BOOL;

#define TRUE 1
#define FALSE 0

定义好之后,就可以像使用基本类型数据一样使用它了,如下面的代码所示:

BOOL bflag=TRUE;

在实际使用中,typedef 的应用主要有如下4种。

  1. 为基本数据类型定义新的类型名

系统默认的所有基本类型都可以利用 typedef 关键字来重新定义类型名,示例代码如下所示:

typedef unsigned int COUNT;
  1. 为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称

以结构体为例,下面我们定义一个名为 Point 的结构体:

struct Point
{
    double x;
    double y;
    double z;
};

在调用这个结构体时,我们必须像下面的代码这样来调用这个结构体:

struct Point oPoint1={1001000};
struct Point oPoint2;

在这里,结构体 struct Point 为新的数据类型,在定义变量的时候均要向上面的调用方法一样有保留字 struct,而不能像 int 和 double 那样直接使用 Point 来定义变量。现在,我们利用 typedef 定义这个结构体,如下面的代码所示:

typedef struct tagPoint
{
    double x;
    double y;
    double z;
} Point;

在上面的代码中,实际上完成了两个操作:
1、定义了一个新的结构类型,代码如下所示:

struct tagPoint
{
    double x;
    double y;
    double z;
} ;

其中,struct 关键字和 tagPoint 一起构成了这个结构类型,无论是否存在 typedef 关键字,这个结构都存在。

2、使用 typedef 为这个新的结构起了一个别名,叫 Point,即:

typedef struct tagPoint Point

因此,现在你就可以像 int 和 double 那样直接使用 Point 定义变量,如下面的代码所示:

Point oPoint1={1001000};
Point oPoint2;
  1. 为数组定义简洁的类型名称

它的定义方法很简单,与为基本数据类型定义新的别名方法一样,示例代码如下所示:

typedef int INT_ARRAY_100[100];
INT_ARRAY_100 arr;
  1. 为指针定义简洁的名称

对于指针,我们同样可以使用下面的方式来定义一个新的别名:

typedef char* PCHAR;
PCHAR pa;

对于上面这种简单的变量声明,使用 typedef 来定义一个新的别名或许会感觉意义不大,但在比较复杂的变量声明中,typedef 的优势马上就体现出来了,如下面的示例代码所示:

int *(*a[5])(int,char*);

对于上面变量的声明,如果我们使用 typdef 来给它定义一个别名,这会非常有意义,如下面的代码所示:

// PFun是我们创建的一个类型别名
typedef int *(*PFun)(int,char*);
// 使用定义的新类型来声明对象,等价于int*(*a[5])(int,char*);
PFun a[5];

typedef 两大陷阱

陷阱一:

记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:

先定义:

typedef char* PSTR;

然后:

int mystrcmp(const PSTR, const PSTR);

const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const

原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const

简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。

陷阱二:

typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:

typedef static int INT2; //不可行

编译将失败,会提示“指定了一个以上的存储类”。

const 解析

const 与 define 的区别在下方!!!

C / C++:const 关键字的作用 <---- 点击进入

const 修饰指针的4种变化 <---- 点击进入

C++:const成员函数的使用细则 <---- 点击进入


知识点习题(内含:const 与 #define 的对比)

  1. test.c文件中包括如下语句:
#define ptr1 int*
typdef int* ptr2;
ptr1 n1, n2;
ptr2 n3, n4;

正确答案:

  • 前者展开后的结果是: int* n1, n2;,类似于int* n1, int n2;
  • 后者展开后的结果是: int* n3, n4;,类似于int* n1, int* n2;

答案解析:

区别的实质是 #define 与 typedef的含义不同

  • #define 只是简单的字符串替代。
  • typedef则是类型的重新定义,其所定义的类型是一体的。

  1. 用宏定义求三个数中的最大值
#define MAX(a,b,c) (a>b ? (a>c?a:c) : (b>c?b:c))

  1. 用const定义一个常量和用define定义一个常量有什么区别?

正确答案:

  • 编译器处理阶段不同
  1. 宏定义是一个“编译时”概念,在预处理阶段展开(在编译时把所有用到宏定义值的地方用宏定义常量替换),不能对宏定义进行调试,生命周期结束于编译时期
  2. const 常量是一个“运行时”概念,在程序运行使用,类似于一个只读行数据。(只读变量)
  • 存储方式不同
  1. 宏定义是直接替换,不会分配内存,存储与程序的代码段中
  2. const常量需要进行内存分配
  • 类型和安全检查不同
  1. 宏定义是字符替换,没有数据类型的区别,同时这种替换 没有类型安全检查可能产生边际效应等错误(------>边际效应不懂就点
  2. const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查
  • 定义域不同
void f1 ()
{
    #define N 12
    const int n 12;  
}

void f2 ()
{
    cout << N <<endl;	// 正确,N已经定义过,不受定义域限制
    cout << n <<endl;	// 错误,n定义域只在f1函数中
}
  • 是否可以做函数参数
  1. 宏定义不能作为参数传递给函数
  2. const常量可以在函数的参数列表中出现
  • 定义后能否取消
  1. 宏定义可以通过 #undef 来使之前的宏定义失效
  2. const常量定义后将在定义域内永久有效
void f1()
{
  #define N 12
  const int n = 12;
  
  #undef N //取消宏定义后,即使在f1函数中,N也无效了
  #define N 21//取消后可以重新定义
}

C++ 语言可以用const 来定义常量,也可以用#define 来定义常量,但是前者比后者有更多的优点。


  1. 如何用宏定义得到一个字的高位和低位字节?
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值