#ifndef...#endif 的用法

来源:互联网 发布:mysql 小于转义 编辑:程序博客网 时间:2024/04/30 08:45

学着写头文件(其实是烧写芯片用到),发现c语言的宏定义里面有的东西需要理解,查了资料之后记下来,这里先说#ifndef…#endif

背景知识

C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。
在c语言中,对同一个变量或者函数进行多次声明是不会报错的。
#ifndef…#endif属于预处理功能中三种(宏定义,文件包含和条件编译)中的第三种—-条件编译

一般格式

#ifndef <标识>#define <标识>............#endif

<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前面加下划线,并把文件名中的“.”也变成下划线,如:stdio.h

#ifndef _STDIO_H#define _STDIO_H......#endif

作用(重复引用的两种情况)

  • 如果h文件里只是进行了声明工作,即使不使用#ifndef宏定义,一个c文件多次包含同一个h文件也不会报错。例如:一个工程里面,同时有a.cpp,b.h,c.h,d.h。其中,a.cpp包含了b.h和c.h的头文件,b.h和c.h又都包含了d.h的头文件,那么编译过程就会造成c.h头文件的重复引用(头文件重复引用只是增加了编译工作的工作量,不会引起太大的问题,仅仅是编译效率低一些)。这种情况下,如果头文件加了#ifndef,会避免重复编译,但不加的话也仍旧是不会报错的。
  • 如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,例如:一个工程里面,同时有a.cpp,b.h,c.h,d.h。其中,a.cpp包含了b.h和c.h的头文件,b.h和c.h又都定义了int m(虽然这种方式不被推荐,但确实是C规范允许的),这样m变量会被编译两次,如果头文件不加#ifndef,那么编译过程会出现变量重复定义的错误。如果头文件加了#ifndef,则不会出现这种错.

条件编译的几种形式(百度)

“ 条件编译”命令允许对程序中的内容选择性地编译,即可以根据一定的条件选择是否编译。条件编译的命令主要有以下几种 :
形式1

 #ifndef 标识符 程序段 1 #else程序段 2 #endif它的作用是当 “ 标识符”没有由# define定义过了。则编译“ 程序段 1 ” 。 否则编译“ 程序段 2 ” 。其中如果不需要编译“ 程序段 2 ”。则上述形式可以变换为: #ifndef 标识符程序段 1 #endif

形式2

 #ifndef 标识符 # define 标识符程序段 1 #else程序段 2 #endif它的作用是当 “ 标识符 没有由# define定义过。 则编译“程序段 1”。否则编译“程序段 2” 。同样当无“ 程序段2 ”时。(作用与形式1完全相同)则上述形式变换为: # ifndef 标识符 # define 标识符程序段 1 #endif

形式3

 #if 表达式程序段 1 #else 程序段 2 #endif它的作用是 当“表达式”值为真时。编译程序段1。否则则编译程序段2。同样 当无程序段 2时,则上述形式变换为 : #if 表达式程序段 1 #endif

以上三种形式的条件编译预处理结构都可以嵌套使用。 当#else后嵌套 #if 时,可以使用预处理命令 # elif , 它相当于 #else#if。在程序中使用条件编译主要是为了方便程序的调试和移植。

补充:带参数的宏定义(定义变量的相信大家都会~)

格式:
#define宏名(参数表) 字符串
例如:#define S(a,b) a*b
area=S(3,2);第一步被换为area=a*b; ,第二步被换为area=3*2;
类似于函数调用,有一个哑实结合的过程:

  • 实参如果是表达式容易出问题
    #define S(r) r*r
    area=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b;
    正确的宏定义是#define S(r) ((r)*(r))
  • 宏名和参数的括号间不能有空格
  • 宏替换只作替换,不做计算,不做表达式求解
  • 函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
  • 宏的哑实结合不存在类型,也没有类型转换。
  • 宏展开使源程序变长,函数调用不会
  • 宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)
0 0