1.预处理指令
C编译器在对源程序进行编译之前,会进行编译预处理。这一步骤由C预处理器(C Preprocessor)完成。所有的预处理器命令都以#开头。预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到取消它的预处理出现位置或文件末尾。
指令 | 描述 |
#define | 定义一个预处理宏 |
#undef | 取消宏定义 |
#ifdef | 判断某个宏是否已定义,若已定义,则执行后续语句 |
#ifndef | 判断某个宏是否未定义,若未定义,则执行后续语句 |
#if | 条件判断,同C语句中的if |
#elif | 条件判断,同C语句中的else if |
#else | 条件判断,同C语句中的else |
#endif | 条件判断结束语句,#ifdef、#ifndef‘、#if结尾 |
#include | 包含文件命令 |
#line | 标志该语句所在行号和文件名 |
#warning | 显示编译器警告信息 |
#error | 显示编译器错误信息 |
#pragma | 说明编译器信息 |
预定义宏
ANSI C定义了许多宏
宏 | 描述 |
FILE | 当前文件名,类型为字符串常量 |
LINE | 当前行号,类型为十进制常量 |
DATE | 当前日期,类型为字符串常量,格式“MMM DD YYYY” |
TIME | 当前时间,类型为字符串常量,格式“HH:MM:SS” |
实例:
printf("File :%s\n", __FILE__ ); printf("Line :%d\n", __LINE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ );
运行结果:
File :main.c Line :6 Date :May 10 2016 Time :15:16:55
预处理器运算符号
(1)宏延续运算符(\)
一个宏太长,在当行容纳不下是,可使用宏延续运算符(\),使其延续到下一行。
(2)字符串常量化运算符(#)
在宏定义中,需要把一个宏的参数转换为字符串常量时使用。
(3)标记粘贴运算符(##)
在宏定义中,可以使宏定义中两个地理的标记被合并为一个标记
(4)defined()运算符
用于确定一个标识符是否已经使用#define定义过。定义则为真,为定义则为假。
实例:
#define THREE1 3 #define add(a,b) printf(#a" add "#b " = %d",THREE##a) int main(int arg,char *argv[]){ #if defined THREE1 add(1,2); #endif // defined return 0; }
运行结果:
1 add 2 = 3
宏定义
(1)不带参数的宏定义
格式:#define 宏名称 字符串
#define COUNT 5
效果:在编译预处理时,会将宏名称替换为对应的字符串。常用用于定义常量和防止头文件重复加载。
实例:
#ifndef _FILE_INT_ #define _FILE_INT_ #include "int.h" #endif // _FILE_INT_
(2)带参数的宏定义
格式:#define 宏名称(形参一,形参二,....) 字符串
#define sum(num1,num2) ((num1)+(num2))
效果:同上
(3)宏取消
格式:#undef 宏名称
(4)使用注意
编译预处理只会执行简单的替换操作,不会进行逻辑运算。
(5)与函数运算的区别
宏定义不涉及存储空间的分配,是在编译之前进行的,故彼函数执行效率更高。
条件编译
控制部分代码是否参与编译(只有被编译的代码被执行)。
格式:
#if 条件1 执行语句1 #elif 条件2 执行语句2 #else 条件3 执行语句3 #endif
文件包含
将一个文件的全部内容拷贝到目标文件中
(1)#include <文件名>
直接在C语言函数库头文件所在的目录中寻找文件
(2)#inlcude "文件名"
一次在源程序当前目录下->系统path路径中->C语言库函数文件所在目录寻找。
#line
可用于修改__LINE和__FILE__
#line 1 "linechange.c" printf("line:%d, flie:%s\n",__LINE__,__FILE__);
运行结果:
line:1, flie:linechange.c
#warning,#error
分别用于在编译时显示警告和错误信息
格式:#warning “warning”;#error “error”
ps:如果给出的是warning编译会继续,是error编译会终止
2.typedef
用于为类型取一个新的名字。它由编译器执行解释。
实例:
typedef char * string; string str = "字符串"; printf("%s",str);
也可以用于用户自定义的数据类型取一个新名字。
typedef struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } Book; Book book;
3.extern和static
作用于变量
(1)extern
在方法体中,带有关键字extern的变量。可以在别的方法和文件中进行访问。
(2)static
带有关键字static的全局变量为私有全局变量,仅限于当前文件访问。
带有关键字static的局部变量,只会创建一次,且生命周期至程序结束时。
实例:
int main(int arg,char *argv[]){ for(int i = 0;i < 5;i ++) { test(); } return 0; } void test(){ static int a = 0; a ++; int b = 0; b ++; printf("a = %d\tb = %d\n",a,b);
运行结果:
a = 1 b = 1 a = 2 b = 1 a = 3 b = 1 a = 4 b = 1 a = 5 b = 1
作用于函数
(1)extern
表示函数为外部函数可以在其他文件中使用。extern关键字可省略。
(2)static
申明函数为内部函数(或静态函数),只能在其定义的文件中使用。