之前我们说过,源程序需要经过预处理、编译、汇编、链接才会变成可执行程序,预处理阶段完成的是预处理操作,本质上是一种替换操作。
宏
不带参宏
宏常量
宏常量是用 #define 定义的宏,只能在一行内表达,如果要在多行内表达,则需要加上连接符\。比如:
#define PI 3.14
宏常量很多情况下可以用来定义文件路径。但要记住:宏只是简单的替换操作
宏类型
有时候,也会用宏来定义一种合成的类型名。如:
#include CHAR_POINTER char *
但要记住:宏只是简单的替换操作,不要和 typedef 弄混
带参宏
宏函数
有时候,对于一些简单的函数也可以利用宏来实现。如:
#define MAX(a,b) a>b?a:b
宏名和参数之间不能出现空格。虽然这样可以简化代码,减少程序调用,但是编译文件会很大。
仍然要记住:宏只是简单的替换操作
取消宏
取消宏常量,宏类型,宏函数
对于已经定义的宏常量,宏类型和宏函数来说,取消宏定义都只有一句话:
#undef macroname
预定义宏
在 C 语言中,还存在着一些内置的已经定义的宏,如:
__DATE__ | 进行预处理的日期 |
__FILE__ | 代表当前源代码文件名的字符串文字 |
__LINE__ | 代表当前源代码中的行号的整数常量 |
__TIME__ | 源文件编译时间 |
__func__ | 当前所在函数名 |
条件编译
在跨平台开发的时候,有时候会根据条件选择性的进行编译,这就是条件编译。
单双路
一般结构为:
#ifdef
......
#else
......
#endif
或者是:
#ifndef
......
#else
......
#endif
单双多路
一般结构为:
#if logical statement
......
#elif logical statement
......
#elif logical statement
......
#endif
#include
在 main 之前除了条件编译之外,一般都会有 #include 语句,这就是头文件包含。
包含方式
包含是指被包含的文件全部包含到当前的文件中。包含方式一般有两种:
<>
使用这种方式是指从指定路径中搜索并包含头文件。
""
使用这种方式是指从当前工程路径中搜索并包含头文件,当前工程路径下不存在的话,才到系统路径下搜索并包含。
多文件编程
多文件编程会增加程序的可读性,除了方便管理之外还能够增加文件的可移植性和保密性。
这里以一个简单的图示简单说明一下:
- C 语言是以文件为单位进行编译的,编译期间只需要进行函数声明即可
- 链接阶段提供实现就能够生成可执行文件
- else.h 中的条件编译语句是为了避免头文件重复包含
关于 #
利用 # 创建字符串
如果要创建类似 "str1",“str2”,"str3" 这样的字符可能就需要 # 运算符。看下边的程序:
#include <stdio.h>
#define str(x) "str"#x
int main()
{
printf("%s\t%s\t%s",str(1),str(2),str(3));
return 0;
}
结果为:
str1 str2 str3
以上的结果是由于类似于 “abc”"def""ghi" 这样的字符串是合理的。而 # 号作为一个预处理运算符,它能够将待替换符转化为字符串。
利用 ## 进行预处理参数粘合
看下边的程序:
#include <stdio.h>
#define SUM(a,b) (a##a+b##b)
#define XVAR(n) x##n
int main()
{
int XVAR(1) = 1,XVAR(2) = 2;
printf("SUM(1,2) = %d\n",SUM(1,2));
printf("XVAR(1) = %d,XVAR(2) = %d\n",x1,x2);
printf("&XVAR(1) = %p,&XVAR(2) = %p\n",&XVAR(1),&XVAR(2));
printf("&x1 = %p,&x2 = %p",&x1,&x2);
return 0;
}
结果为:
SUM(1,2) = 33
XVAR(1) = 1,XVAR(2) = 2
&XVAR(1) = 0060FEAC,&XVAR(2) = 0060FEA8
&x1 = 0060FEAC,&x2 = 0060FEA8
还可以将上边的程序改为:
#include <stdio.h>
#define XVAR(n) x##n
#define PRINT_VAR(n) printf("XVAR("#n") = %d",x##n);
#define POINTER_VAR(n) printf("&XVAR("#n") = %p",&XVAR(n));
#define POINTER_X(n) printf("&x"#n" = %p",&x##1);
int main()
{
int XVAR(1) = 1,XVAR(2) = 2;
PRINT_VAR(1);
putchar(10);
PRINT_VAR(2);
putchar(10);
POINTER_VAR(1);
putchar(10);
POINTER_VAR(2);
putchar(10);
POINTER_X(1);
putchar(10);
POINTER_X(2);
return 0;
}