c语言预处理

Python022

c语言预处理,第1张

其实百度文库也讲得挺明白的,你可以打开一个.h的头文件看看里面,对应这三点,就很清楚了。一.宏定义1.不带参数的宏定义: 宏定义又称为宏代换、宏替换,简称“宏”。 格式: #define 标识符 字符串 其中的标识符就是所谓的符号常量,也称为“宏名”。 预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。 掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。 即在对相关命令或语句的含义和功能作具体分析之前就要换: 例: #define PI 3.1415926 把程序中出现的3.1415926全部换成PI 说明: (1)宏名一般用大写 (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义 (3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。 (4)宏定义末尾不加分号; (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。 (6)可以用#undef命令终止宏定义的作用域 (7)宏定义可以嵌套 (8)字符串" "中永远不包含宏 (9)宏定义不分配内存,变量定义分配内存。 2.带参数的宏: 除了一般的字符串替换,还要做参数代换 格式: #define 宏名(参数表) 字符串 例如:#define S(a,b) a*b area=S(3,2);第一步被换为area=a*b,第二步被换为area=3*2类似于函数调用,有一个哑实结合的过程: (1)实参如果是表达式容易出问题 #define S(r) r*r area=S(a+b)第一步换为area=r*r,第二步被换为area=a+b*a+b正确的宏定义是#define S(r) (r)*(r) (2)宏名和参数的括号间不能有空格 (3)宏替换只作替换,不做计算,不做表达式求解 (4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存 (5)宏的哑实结合不存在类型,也没有类型转换。 (6)函数只有一个返回值,利用宏则可以设法得到多个值 (7)宏展开使源程序变长,函数调用不会 (8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值) 编辑本段二. 文件包含一个文件包含另一个文件的内容 格式: #include "文件名" 或 #include <文件名>编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。 编译以后只得到一个目标文件.obj 被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。 修改头文件后所有包含该文件的文件都要重新编译 头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义: (1)一个#include命令指定一个头文件; (2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行; (3)包含可以嵌套; (4)<文件名>称为标准方式,系统到头文件目录查找文件, "文件名"则先在当前目录查找,而后到头文件目录查找; (5)被包含文件中的静态全局变量不用在包含文件中声明。 编辑本段三. 条件编译有些语句行希望在条件满足时才编译。 格式:(1) #ifdef 标识符 程序段1 #else 程序段2 #endif 或 #ifdef 程序段1 #endif 当标识符已经定义时,程序段1才参加编译。 格式:(2) #ifndef 标识符 格式:(3) #if 表达式1 程序段1 #else 程序段2 #endif 当表达式1成立时,编译程序段1,当不成立时,编译程序段2。 使用条件编译可以使目标程序变小,运行时间变短。 预编译使问题或算法的解决方案增多,有助于我们选择合适的解决方案。 此外,还有布局控制:#pragma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。

预处理 功能主要包括:

宏定义,文件包含,条件编译三部分。

分别对应宏定义命令,文件包含命令,条件编译命令 三部分实现。

预处理过程读入源代码,检查包含预处理指令的语句和宏定义,

并对源代码进行响应的转换。预处理过程还会删除程序中的注释

和多余的空白字符。

预处理指令是以#号开头的代码行。

#号必须是该行除了任何空白字符外的第一个字符。

#后是指令关键字,在关键字和#号之间允许存在任意

个数的空白字符。整行语句构成了一条预处理指令,

该指令将在编译器进行编译之前对源代码做某些转换。

 

指令             用途

 #             空指令,无任何效果

 #include       包含一个源代码文件

 #define        定义宏

 #undef         取消已定义的宏

 #if           如果给定条件为真,则编译下面代码

 #ifdef         如果宏已经定义,则编译下面代码

 #ifndef        如果宏没有定义,则编译下面代码

 #elif          如果前面的#if给定条件不为真,当前条件为真,则编译下面代码

 #endif         结束一个#if……#else条件编译块

 #error         停止编译并显示错误信息

 #else          条件编译的否则选项

 #error         指令将使编译器显示一条错误信息,然后停止编译。

 #line          指令可以改变编译器用来指出警告和错误信息的文件号和行号。

 #pragma        指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。

文件包含

在程序中包含头文件有两种格式:

#include <my.h>

#include "my.h"

第一种方法是用尖括号把头文件括起来。

这种格式告诉预处理程序在编译器自带的或

外部库的头文件中搜索被包含的头文件。

第二种方法是用双引号把头文件括起来。

这种格式告诉预处理程序在当前被编译的

应用程序的源代码文件中搜索被包含的头文件,

如果找不到,再搜索编译器自带的头文件。

采用两种不同包含格式的理由在于,编译器是

安装在公共子目录下的,而被编译的应用程序

是在它们自己的私有子目录下的。一个应用程序

既包含编译器提供的公共头文件,也包含自定义

的私有头文件。采用两种不同的包含格式使得编

译器能够在很多头文件中区别出一组公共的头文件。 

举个例子:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#define SIX 6

#define SEVEN 7

#define Cube(x) (x)*(x)*(x)

#define VERSION "tzs"

#define PASTE(n) "最终胜利者是:"#n

#define NUM(a,b,c) a##b##c

#define STR(a,b,c) a##b##c

#define DEBUG 1

int main()

{

    int i

    i = SIX + SEVEN

    printf("i = %d\n",i)

    i = (SIX * SEVEN)

    printf("i = %d\n",i)

    i = Cube(3)

    printf("i = %d\n",i)

    printf("%s",VERSION)

    printf("%s",PASTE(桃子))

    puts(PASTE(yy/))

    puts(PASTE(xx))

    printf("%d\n",NUM(1,2,3))

    //printf("%s\n",STR("aa","bb","cc"))

    #if DEBUG

        printf("Debugging\n")

        printf("Debugging2222\n")

    #endif

        printf("Running\n")

    #if defined DEBUG

        printf("yes\n")

    #endif

    #if !defined JJ

        printf("no JJ\n")

    #endif

}