黑马程序员---C语言学习笔记之预处理指令、宏和条件编译

------Java培训、Android培训、iOS培训、.Net培训--------

一、预处理指令的概念及分类


1.基本概念

以“#”号开头指令都称为【预处理指令】。如包含命令#include等。在源程序中这些命令都放在函数之外。而且一般都放在源文件的前面,他们称为【预处理部分】

 

所谓预处理是指在进行编译的第一道扫描(词法扫描和语法扫描)之前所做的工作,预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分做处理,处理完毕自动进入对源程序的编译。

C语言提供了多种预处理功能。如宏定义,文件包含,条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。


二、宏的概念及无参宏定义方法


1.宏的概念

被定义为“宏”的标识符称为“宏名”,在编译预处理时,都用宏定义中的字符串取代换,这称为“宏代换”或“宏展开”

 例如 #define Row 10 //此处Row就是一个宏

 

宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。在C语言中,“宏”分为【有参宏】和【无参宏】

 

无参宏的宏名不带参数,其定义一般形式为:

 

#define标识符字符串

 

其中"#"表示这是一掉预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”位所定义的宏名。“字符串”可以使常熟,表达式、格式串等

 

例如:

//定义一个宏
#define PI 3.1415926
#define Area PI*4
#include 
 
int main(int argc, const char * argv[])
{
 
    printf("area = %0.4f",Area);//预处理时,Area会被替换成3.1415926*4
    return 0;
}

 

【注意】

1、宏定义式一个预处理指令,结尾不需要加“;

2、宏定义替换问题

例如:

//定义一个宏
#define PI 3.1415926
#define Sum a*b+2*b
#include 
 
int main(int argc, const char * argv[])
{
 
    int a = 2,b =3;
    
    printf("a2*Sum+ 3*Sum =%0d\n",2*Sum+ Sum);//预处理时,2*Sum+ Sum会被替换成2*a*b+2*b+a*b+2*b = 30而不是2*(a*b+2*b) +(a*b+2*b) = 36.
    printf("2*a*b+2*b+a*b+2*b = %d\n", 2*a*b+2*b+a*b+2*b);
    printf("2*(a*b+2*b) +(a*b+2*b) = %d", 2*(a*b+2*b) +(a*b+2*b));
    return 0;
}


打印结果:

a2*Sum+ 3*Sum = 30

2*a*b+2*b+a*b+2*b = 30

2*(a*b+2*b) +(a*b+2*b) = 36


三、有参宏的定义和使用方法

1、有参宏的定义方法

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

 

带参宏定义的一般形式为:

define 宏名(参数表字符串

例如:

//定义一个带参宏
#define Add(x,y) x+y
#include 
 
int main(int argc, const char * argv[])
{
    printf("x + y = %d", Add(10, 20));
    return 0;
}


 

打印结果:

x + y = 30

 

2、注意事项

1)宏的形参之间可以出现空格,但是【宏名】和【形参】之间不能出现空格

例如:

#define Add (x,y) x+y //报错
#define Sub(x, y) x + y //不报错
 

2)在带参宏定义中,形式蚕食不分配内存单元,因此不必做类型定义,而宏调用中的实参有具体值,要用他们去代换形参,因此必须做类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”,而带参宏中,只是符号代表,不存在值传递的问题。

 

3)在宏定义中的形参是标识符,而宏调用的实参可以是表达式

 

4)在宏定义中,【字符串内的形参通常要用括号括起来】以避免出错,

例如:

 
#define Mul(x,y) x*y 
 
#include 
 
int main(int argc, const char * argv[])
{
    int a = 2, b = 3;
    printf("x + y = %d", Mul(a + b, a*b));
    return 0;
}


打印结果:

x + y = 20

 

期待结果:(2+3)*(2*3) =30,但是宏展开的时候替换成了2+3*2*3 = 20

因此【字符串内的形参通常要用括号括起来】以避免出错,

如下:

#define Mul(x,y) (x)*(y) 
 
#include 
 
int main(int argc, const char * argv[])
{
    int a = 2, b = 3;
    printf("x + y = %d", Mul(a + b, a*b));
    return 0;
}

 

打印结果:

x + y = 30


四、typedef#define的区别

1typedef#define的区别

 

例如:

//定义一个宏
#defineMYINT int*
//给int型起一个别名
typedef int* MYINT2;
 
#include 
 
int main(int argc, const char * argv[])
{
    //使用宏定义变量
    int num = 20;
    MYINT a, b;//a是一个指针,b是一个普通变量,在宏展开的时候替换为int *a,b
   a = #
   
    printf("a = %d\n",*a);
    //b =#
    //printf("b = %d\n",*b);//报错
   b = num;
    printf("b = %d\n",b);//打印结果b = 20
    //使用别名定义变量,不是简单的替换字符串,而是给类型起了个别名
    MYINT2 c, d;
   c = #
    //d = num; //报错
    d = #  //不会报错
    printf("c = %d",*c);
    return 0;
}


五、条件编译的概念及优点

1.为什么要使用条件编译?

1)按不同的条件取编译不同的程序部分,因而产生不同的目标代码文件,有利于程序的一直和调试

 

2)条件编译当然也可以用条件语句来实现,但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用了条件编译,则根据条件只编译其中的程序段1或程序段4,生成的目标程序较短。

 

2.条件编译

发生在预处理阶段,在编译前做的事情

【核心】:根据条件编译指定的代码

条件不同,编译的部分也不同,生成的目标文件(.o)大小也不同

#define score 89
#include 
 
int main(int argc, const char * argv[])
{
   /* intscore = 89;
    //用if条件语句实现,编译后(.o)文件的大小是1,172 bytes
    score /=10;
 
    if (score < 6) {
        printf("E");
    } else if (score < 7) {
        printf("D");
    }
    else if (score < 8) {
        printf("C");
    }
    else if (score < 9) {
        printf("B");
    }
    else{
        printf("A");
    }*/
//使用条件编译,(.o)文件 836 bytes
#if score < 6 //此处不能使用普通变量,要用宏定义
     printf("E");
#elif score < 7
     printf("D");
#elif score < 8
     printf("C");
#elif score < 9
     printf("B");
#else
     printf("A");
#endif //这个必须有,有#if配对
    return 0;
}


 

3#ifdef用来判断某个宏是否定义

例如:

    int a = 0;
#ifdef AMOS//检测宏DEBUG1是否定义,若果定义了,a=10,对应的#ifndef,如果没有定义
    a = 10;
#else
    a = 100;
#endif
    printf("a = %d\n",a);


 

4、使用条件编译调试程序

 

#define AMOS 0
#include 
//使用条件编译调试程序
 
#if AMOS == 1
//显示调试信息
#define Log(format,...) printf(format,## __VA_ARGS__);
#else
//不显示调试信息
#define Log(format,...)
#endif
 
 
 
int main(int argc, const char * argv[])
{
    int a = 0;
#ifdef DEBUG1 //检测宏DEBUG1是否定义,若果定义了,a=10,对应的#ifndef,如果没有定义
    a = 10;
#else
    a = 100;
#endif
    Log("------------------>a = %d\n", a);
   return 0;
}


打印结果:

当AMOS = 1时:

------------------>a= 100

当AMOS = 0时:

没有打印任何信息



你可能感兴趣的:(黑马程序员---C语言学习笔记之预处理指令、宏和条件编译)