C语言拾遗-C语言预处理-宏定义

#define

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

  • c语言中用到很多宏定义 ,为了头文件被重复用到#ifndef  #define,#ifdefine  edfif等条件编译
  • 宏不是语句,结尾不用加“;”,否则会被替换进进程中
  • #表示这是一条预处理指令
  • 如果写宏不止一行,则在结尾加反斜杠使多行能连接上,但第二行要对齐,否则空格也会作为替换文本的一部分

在C或C++语言中,“宏”分为有参数和无参数两种。

无参宏

无参宏即宏名之后不带参数,只是简单的文本替换。其定义的一般形式为:

#define 标识符 字符串

#define与typedef区别

  • 两者都可以表示数据类型 
#define INI1 int 
typedef int INT2 

 

  • 但有时候也会有区别比如定义指针类型的变量时
1 #define INT1 int *
2 typedef int * INT2;
3 INT1 a1, b1;
4 INT2 a2, b2;

 

INT1 a1,b1;被替换后为 int *a1,b1;即一个指向int类型的指针一个int类型的变量

INT2  a2,b2;则是两个指向int类型的指针

有参宏

c语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

带参数的宏定义,宏名中不能有空格,宏名与形参表之间也不能有空格,而形参表中形参之间可以有空格

有参宏实现一个数的平方

#define COUNT(M) M*M
int x=6;
print(COUNT(x+1));
print(COUNT(++X));

结果输出:13和56 而不是函数的输出49和49。原因在于预编译器不进行计算,只是进行简单的文本替换,COUNT(x+1)被替换成COUNT(x+1*x+1),CUNT(++x)被替换成++x*++x即为7*8=56而不是想要的7*7=49,连续前置自加加两次。解决办法是用括号将整个替换文本及每个参数用括号括起来但即便是加上括号也不能解决第二种情况,所以解决办法是尽量不使用++、--等符号。

函数实现一个数的平方

int count(int x)
{
    return x*x
}

有参宏与函数区别

在宏定义#define COUNT(M) M*M中的形参不分配内存单元,不做类型定义,只是简单的文本替换,而函数int count(int x)中形参x是局部变量,会在栈区分配内存单元,所以要做类型定义,而且实参与形参之间是值传递。而宏只是符号代换,不存在值传递。

宏定义也可以定义表达式或多个语句

#define AB(a,b) a=i+5;b=j+3;   宏定义多个语句
int i=3,j=5;
int m-0,n=0;
AB(m,n);       //宏替换后为m=i+5,n=j+3;
print("m=%d,n=%d",m,n);

输出结果:m=8,n=8。

#运算符

#的作用就是将#后边的宏参数进行字符串的操作,也就是将#后边的参数两边加上一对双引号使其成为字符串。例如a是一个宏的形参,则替换文本中的#a被系统转化为"a",这个转换过程即为字符串化。

#define TEST(param) #param
char *pStr=TEST(123);
printf("pSrt=%s\n",pStr);

输出结果为字符  ”123“

##运算符

##运算符也可以用在替换文本中,它的作用起到粘合的作用,即将两个宏参数连接为一个数

#define TEST(param1,param2) (param1##param2)
int num =TEST(12,34);
printf("num=%d\n",num);

输出结果为:num=1234

成熟软件中常用的宏定义

  • 防止头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件的内容

#endif
  • 得到一个制定地址上的一个字节或字
#define MEM_B(X) (*((byte*)(x)))
#define MEM_W(X) (*((word*)(x)))
  • 求最大值与最小值
#define MAX(x,y)  ((x)>(y)?(x):(y))
#define MIN(x,y)  ((x)<(y)?(x):(y))
  • 得到一个结构体中field所占用的字节数
#define FSIZ(type,field)  sizeof(((type*)0)->field)

#undef

这条预处理指令用于移除一个宏定义。

#undef name

如果一个现存的名字需要被重新定义,那么它的旧定义首先必须用#undef移除。

参考链接

  • https://www.cnblogs.com/shmilxu/p/4837373.html
  • https://www.cnblogs.com/southcyy/p/10155049.html
  • 《C和指针》(14.2)
  • GB/T 15272-1994 (6.8.3)

你可能感兴趣的:(C语言)