C语言宏

简介:

了解C语言的宏,我们首先得了解编译器编译C语言程序的过程:

C语言编译过程

其中预处理器工作有:

(1) 文件包含:可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
(2) 条件编译:预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外。
(3) 宏展开:预处理器将源程序文件中出现的对宏的引用展开成相应的宏定义。

预处理中宏的作用:
(1)方便程序的修正:将某个特定数量在程序中出现的所有实例统统加以修改;

(2)提高程序的运行效率:C语言在实现函数调用时会带来重大系统开销,宏可以实现一种这样的程序块:它看上去像函数,但却没有函数调用的开销。

 

宏有有两种定义格式:
(1) 简单的宏定义:#define <宏名> <字符串>                                  //对应宏作用1

#define PI 3.1415926

#define PI 3.14
(2) 带参数的宏定义:#define <宏名> (<参数表>) <宏体>                //对应宏作用2

#define f(x) x

 

宏应该注意的地方:

(1)不能忽视宏定义中的空格:

  例子:下面宏定义中 f 是否带了一个参数?

#define f (x) ((x)-1)

 答案两种:f(x) = ((x) - 1) 或者 f=(x)  ((x)-1)

在上述定义中f = (x)  ((x) - 1)是正确的(虽然无法使用),因为 f 和后面的(x)之间多了一个空格。f (3) = 2;

因此在定义宏的时候,要严格的注重空格的使用,一般来讲带参数的宏,其参数列表与宏名要相连。

(很有趣:定义#define f(x) ((x) - 1), 调用f(3) = f (3) = 2)

 

(2)宏不是函数,需注重括号的使用:

例子:

#define abs(x) x > 0 ? x : -x //正确使用:#define abs(x) (((x)>0) ? (x) : (-x))

对abs(a-b)求值,宏被展开为:a-b >0 ? a-b : -a-b

例子中的-a-b相当于(-a)-b,而不是我们期望的-(a-b);因此,在定义宏的时候我们最好把每个参数都用括号括起来,整个表达式也括起来。

 

(3)宏不是类型定义:

看下面代码:

#define NEWTYPE struct newType
NEWTYPE a;
NEWTYPE b,c;

我们只需要改动一行代码,就可以改变a,b,c的类型,宏的这种用法有一个有点:可移植性,得到了所有C编译器的支持,但是,我们最好还是用typedef来定义:

typedef struct newType NEWTYPE

因为使用宏会带来意想不到的错误,例如:

#define T1 struct foo*
typedef struct foo *T2;

从定义上看,T1和T2的概念上完全符同,都是指向了foo的指针。但是,当我们试图使用它们来声明多个变量时,就会出现问题:

T1 a, b; //宏扩展:struct foo * a, b;
T2 a, b; //typedef定义:struct foo *a, *b;

可以看见使用宏扩展并不能得到我们想要的东西。

所以,使用类型定义的时候,我们最好不要使用宏,应该使用typedef。

 

对于宏的讲解结束,让我们回过头看看 宏应该注意的地方(1)

#define f (x) ((x)-1)

对于表达式 (x) ((x) -1) 是否能够成为一个合法的C表达式呢?

给出一种合理解:

我们定义:typedef int x;

在这种情况下:(x) ((x) - 1) 等价于 (int) ((int) - 1)

即将-1转换为int类型两次!

目录
相关文章
|
3月前
|
程序员 C语言 UED
详解C语言assert宏
详解C语言assert宏
26 0
|
19天前
|
存储 编译器 Linux
【C语言】自定义类型:结构体深入解析(二)结构体内存对齐&&宏offsetof计算偏移量&&结构体传参
【C语言】自定义类型:结构体深入解析(二)结构体内存对齐&&宏offsetof计算偏移量&&结构体传参
|
1月前
|
编译器 C语言
C语言宏定义(#define定义常量​、#define定义宏​、 带有副作用的宏参数、 宏替换的规则、 宏函数的对比)
C语言宏定义(#define定义常量​、#define定义宏​、 带有副作用的宏参数、 宏替换的规则、 宏函数的对比)
|
1月前
|
程序员 C语言
C语言 宏
C语言 宏
14 0
|
1月前
|
编译器 C语言
嵌入式C 语言函数宏封装妙招
嵌入式C 语言函数宏封装妙招
23 0
|
6月前
|
编译器 C语言 C++
C语言基础教程(宏的使用和多文件编程)
C语言基础教程(宏的使用和多文件编程)
49 0
|
3月前
|
C语言
详解C语言可变参数列表(stdarg头文件及其定义的宏)
详解C语言可变参数列表(stdarg头文件及其定义的宏)
48 0
|
19天前
|
编译器 C语言
C语言中函数宏的三种封装方式详解
C语言中函数宏的三种封装方式详解
47 0
|
4月前
|
C语言
C语言预处理及宏和函数的区别与各自优劣点的详解(下)
C语言预处理及宏和函数的区别与各自优劣点的详解(下)
|
4月前
|
C语言
C语言预处理及宏和函数的区别与各自优劣点的详解(上)
C语言预处理及宏和函数的区别与各自优劣点的详解(上)