C语言:随笔7--预处理命令

以#开头的就是预处理命令。

#include<stdio.h>//标准的输入输出头文件

#define PI 3.1415925//宏定义命令

在源程序中这些命令都是放在函数之外,而且一般都是放在源文件的前面,他们称为预处理部分。(因为他们比源文件更早的被处理到)

一、无参数的宏定义

1、无参数的宏名后不带参数。

其定义的一般形式为:

#define  标识符  字符串//其中“#”表示这是一条预处理命令
凡是以“#”开头的均为预处理命令。define为宏定义命令。”标识符“为多定义的宏名。“字符串”可以是阐述、表达式、格式串等。
//例如
#define PI 3.1415926
//他的作用是指定标识符PI来代替数3.1415926.
//在百你写源程序时,所有的3.1415926都可以由PI代替,而对源程序做编译时,将由预处理程序进行宏代换,即用3.1415926表达式去置换所有的宏名PI,然后再进行编译。

不带参数的宏定义说明:

(1)宏定义是用宏名来表示一个字符串,再宏展开时又以该字符串取代宏名,这只是一种简单的替换,字符串可以是含任何字符,可以是常数,也可以是表达式,预处理程序时对他不做任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。

(2)宏定义不是说明或者语句,在行末不必加分号,如加上分号则连分号也一起置换。

(3)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。#undef 标识符

(4)宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。(用双引号括起来的我们都把他当作常量字符串是要输出出来的)

(5)宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开式由预处理程序层层替换。

(6)习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。(因为习惯上规定变量名用小写)

(7)可用宏定义表示数据类型,使书写方便。 

比如:#define TNTEGER int(用TNTEGER a;就表示int a;)

-----PS:宏定义表示数据类型和用typedef定义数据说明符的区别

区别:宏定义只是简单的字符串替换,是在预处理完成的,而typedef(其实是个语句,后面有分号“;”)是在编译时处理的,他不是作简单的替换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。

用以下实例作比较:

#include<stdio.h>
#define PTN1 char*//PIN1是一个char* 是一个指针形式的字符
typedef char* PIN2;//指针形式的字符为PIN2
void main()
{
    PIN1 x,y;//用PIN1定义x和y//3宏定义替换:char* x,y;(相当于定义x是一个指针而y是一个字符型)
    PIN2 a,b;//用PIN2定义a和b//4而用typedef呢使类型重命名,将char*用PIN2表示,也就是说这里相当于char* a,char* b;所以打印出来不一样
    printf("By #define:%d %d\n\n",sizeof(x),sizeof(y));//分别取他们的大小然后打印。1打印结果4 1
    printf("By typedef:%d %d\n\n",sizeof(a),sizeof(b)); //2打印结果:4  4

}

(8)对“输出格式”作宏定义,可以减少书写麻烦。(比如在输出时用printf打印需要%d、%s一百遍较麻烦)

#include<stdio.h>
#define P printf
#define D "%d\n"
#define F "%f\n"

void main()
{
   int a=5,c=8,e=11;
   float b=3.8,d=9.7,f=21.08;
   P(D F,a,b);
   P(D F,c,d);
   P(D F,e,f);

}

二、带参数的宏定义

C语言允许宏带有参数,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。

对带参数的宏,在调用中,不仅要宏展开,而且要用实参去替换形参。

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

#define 宏名(形参表)  字符串//不带分号“;”

带参宏调用的一般形式为:

宏名(实参表);//带分号“;”

例如:

#define M(y) y*y+3*y//宏定义//参数是y,字符串是y*y+3*y
...
K=M(5);//宏调用//传递给的实参是5,在调用时,实参5去替换形参y。(但是这里跟函数的调用值传递是不一样的,这里是直接的替换)

实例:

#include<stdio.h>
#define MAX(a,b) (a>b?a:b)//a和b是虚有的只是一个替代的符号
void main()
{
    int x,y,max;//定义了类型
    printf("input two numbers:")
    scanf("%d %d",&x,&y);
    max=MAX(x,y);//这里替换为max=(x>y)?x,y;//上边的a和b就被x和y实参化了
    printf("The max is %d\n\n",max);

}

带参数的宏定义说明:

(1)带参宏定义中,宏名和形参表之间不能有空格出现。比如上边就不能写为#define MAX   (a,b)之间不能有空格。

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

(3)在定义宏中的形参是标识符,而宏调用中的实参可以是表达式。(何为表达式呢其实就是一个式子)

#include<stdio.h>
#define SAY(y)  (y)
void main()
{
    int i;
    char say[]={73,32,108,111,118,101,32,102,105,115,104,99,46,99,111,109,3}
    while(say[i])
    {
        say[i]=SAY(say[i]+1);//可以是表达式(刚才打印的各个字符的ASCII码加1)
    }
    printf("\n\t%s\n\n",say);//打印出来I love fishc,com!
}
#include<stdio.h>
#define SAY(y)  (y)^(y)//里边的符号^是异或的意思
void main()
{
    int i;
    char say[]={73,32,108,111,118,101,32,102,105,115,104,99,46,99,111,109,3}
    while(say[i])
    {
        say[i]=SAY(say[i]^say[i]);
    }
    printf("\n\t%s\n\n",say);

}

(4)在宏定义中,字符串内的形参通常要用括号括起来以避免出错。(加括号避免优先级发生改变)

(5)带宏的参和带参数的函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。

三、条件编译

预处理程序提供了条件编译功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。

条件编译有三种潜规则:

第一种:功能是:如果标识符已被#define命令定义过则对程序段1进行编译;否则对程序段2进行编译。

#ifdef  标识符//如果有定义这个标识符的话,那么就执行程序1
    程序段1
#else//没有定义的话就执行2
    程序段2
#endif

 如果没有程序段2(他为空)本格式中的#else可以没有,即可以写为:

#ifdef  标识符//如果有定义这个标识符的话,那么就执行程序
    程序段
#endif

第二种形式:

#ifndef  标识符//如果没有定义这个标识符的话,那么就执行程序1
    程序段1
#else//有定义的话就执行2
    程序段2
#endif

第三种形式:

#if  常量表达式//if 0下边的就不会被编译执行做注释用的多(相当于一个开关,是1就执行程序1,是0就执行程序2)
    程序段1
#else
    程序段2
#endif

猜你喜欢

转载自blog.csdn.net/m0_37957160/article/details/108682379