小白来学C语言之宏定义(#define)

毕竟是小白,从小白视角看可能不会太深,但应该都能看懂。
这篇博客就是也是写给新手的,希望大家都能学懂学好,嘿嘿,写的不好还望大佬勿喷。

可以使用#define 伪指令来定义一个宏。 宏分为不带参数的宏和带参数的宏。
宏定义以#define 关键字后面出现的第一个连续字符序列作为宏名,剩下的部分作为宏体。
宏定义具有文件作用域,不论宏定义出现在文件中的哪个地方,例如函数体内、类型定义内部、名字空间内部等,在它后面的任何地方都可以引用宏

宏的几个特点和注意事项如下。

  1. 宏定义不是C++/C语句,因此不需要使用语句结束符 “;”, 否则它也被看做宏体的一部分。例如:
    例一:正确写法:
#include <stdio.h>
#define PRICE 30
void main(){
   int num , total;
   num = 10;
   total = PRICE*num;
   printf("%d\n",total);
 }

例二:错误写法

#include <stdio.h>
#define PRICE 30;   //注意这边的分号
void main(){
   int num , total;
   num = 10;
   total = PRICE*num; /
   printf("%d\n",total);
 }

例三:正确:这后面的分号就被看作宏体的一部分了

#include <stdio.h>
#define PRICE 30;   //注意这边的分号
void main(){
   int num , total;
   num = 10;
   total = num*PRICE; //注意这边的分号  这句也可以这样写,结果一样 total = num*PRICE; ;
   printf("%d\n",total);
 }

使用方法为:

OUTPUT(I like swimming very much.);

替换结果就是:

cout << “I like swimming very much.”《endl;

  1. 任何宏在编译预处理阶段都只是进行简单的文本特换。不做类型检查和话法检在,这个工作留给编译器进行。参数替换发生在宏扩展之前。
  2. )宏定义可以嵌套。例如:
#define PI3.14
#definePI 2 (2* PI)
  1. 宏不可以调试,因为宏不会进入符号表(符号表是编泽器创建的。在编译时宏已经消失了),即使宏替换后出现了语法错误,编译器也会将错误定位到源程序中而不是定位到具体的某个宏定义中。
  2. 程序里使用双引号括起来的字符串中即使出现了与宏同名的子串,预处理遵过程也不进行替换。
  3. 定义带参数的宏时,宏名和左括号之间不能出现空格,否则使用时会出现问题,但是编译器不会检查出这种错误。例如,宏TEXT如果定义为下面这样是报错的
#include <stdio.h>
#define PRICE 30;
#define TEXT (str)   //注意这边的分号
void main(){
   printf(TEXT(Hello));
 }
  1. 带参数的宏体和各个形参应该分别用括号括起来,以免造成意想不到的错误。例如:
#define SQUARE(x) ((x)* (x))

a= SQUARE(3+ 5):
*************************
a=8*8=64

如果写成

#define SQUARE(x)  x*x
a= SQUARE(3+ 5):
**************************
a=3+5*3+5=23
  1. 不要在引用宏定义的参数列表中使用增量和减量运算行,否则可能导致变量多次求值,且结果可能与预期不符,因为复合表达式中子表达式的求值顺序。因具体编译器的不同而不同。
#define SQUARE(x) ((x)* (x))
int n=5;

int x= SQUARE(n++);

其结果可能是30,也可能是25
  1. 带参数的宏定义不是函数,因此没有函数调用的开销,但是其每次扩展都会生成重复的代码,结果使可执行代码的体积增大。
  2. 当我们不再使用某个宏时,可以使用#undef来取消其定义。否则简单地删除宏定义会带带来许多编译错误,例如:
 #undef TEXT

建议

  1. 虽然宏定义很灵活,并且通过彼此结合可以产生许多变形用法是C++/C程序员不要定义很复杂的宏,宏定义应该简单而清晰
  2. 宏名采用大写字符组成的单词或其缩写序列,并在各单词之间使用 _ 下划线分隔
  3. 如果需要公布某个宏,那么该宏定义应当放置在头文件中,否则放置在实现文件(.cpp) 的顶部:
  4. 不要使用宏来定义新类型名,应该使用typedef, 否则容易造成错误;
  5. 给宏添加注释时请使用块注释(/* */), 而不要使用行注释。因为有些编译器可能会把宏后面的行注释理解为宏体的一部分;
  6. 尽量使用const取代宏来定义符号常量
  7. 对于较长的使用频率较高的重复代码片段,建议使用函数或模板而不要使用带参数的宏定义:而对于较短的重复代码片段,可以使用带参数的宏定义,这不仅是出于类型安全的考虑,而且也是优化与折衷的体现;
  8. 尽量避免在局部范围内(如函数内、类型定义内等)定义宏,除非它只在该局部范围内使用,否则会损害程序的清晰性。

猜你喜欢

转载自blog.csdn.net/weixin_45755332/article/details/107047340