转自:
假如现在要开发一个C语言程序,让它输出红色的文字,并且要求跨平台,在Windows和Linux下都能运行,怎么办呢?
这个程序的难点在于,不同平台下控制文字颜色的代码不一样,我们必须要能够识别出不同的平台。
Windows有专有的宏_WIN32,Linux有专有的宏__linux__,以现有的知识,我们很容易就想到了if-else,请看下面的代码:
#includeint main(){ if(_WIN32){ system("color 0c"); printf("http://c.biancheng.net\n"); }else if(__linux__){ printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m"); }else{ printf("http://c.biancheng.net\n"); } return 0;}
但这段代码是错误的,在Windows下提示__linux__是未定义的标识符,在 Linux下提示_Win32是未定义的标识符。对上面的代码进行改进:
#includeint main(){ #if _WIN32 system("color 0c"); printf("http://c.biancheng.net\n"); #elif __linux__ printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m"); #else printf("http://c.biancheng.net\n"); #endif return 0;}
#if、#elif、#else和#endif都是预处理命令,整段代码的意思是:如果宏_WIN32的值为真,就保留第4、5行代码,删除第7、9行代码;如果宏__linux__的值为真,就保留第7行代码;如果所有的宏都为假,就保留第9行代码。
这些操作都是在预处理阶段完成的,多余的代码以及所有的宏都不会参与编译,不仅保证了代码的正确性,还减小了编译后文件的体积。
这种能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。条件编译是预处理程序的功能,不是编译器的功能。
条件编译有多种形式,下面一一讲解。
#if 命令:
#if 命令的完整格式为:#if 整型常量表达式1 程序段1#elif 整型常量表达式2 程序段2#elif 整型常量表达式3 程序段3#else 程序段4#endif
它的意思是:如常“表达式1”的值为真(非0),就对“程序段1”进行编译,否则就计算“表达式2”,结果为真的话就对“程序段2”进行编译,为假的话就继续往下匹配,直到遇到值为真的表达式,或者遇到#else。这一点和if-else非常类似。
需要注意的是,#if命令要求判断条件为“整型常量表达式”,也就是说,表达式中不能包含变量,而且结果必须是整数;而if后面的表达式没有限制,只要符合语法就行。这是#if和if的一个重要区别。
#elif和#else也可以省略,如下所示:
#includeint main(){ #if _WIN32 printf("This is Windows!\n"); #else printf("Unknown platform!\n"); #endif #if __linux__ printf("This is Linux!\n"); #endif return 0;}
#ifdef 命令:
#ifdef 命令的格式为:
#ifdef 宏名 程序段1#else 程序段2#endif
它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。
也可以省略 #else:
#ifdef 宏名 程序段#endif
VS/VC有两种编译模式,Debug和Release。在学习过程中,我们通常使用Debug模式,这样便于程序的调试;而最终发布的程序,要使用Release模式,这样编译器会进行很多优化,提高程序运行效率,删除冗余信息。
为了能够清楚地看到当前程序的编译模式,我们不妨在程序中增加提示,请看下面的代码:
#include#include int main(){ #ifdef _DEBUG printf("正在使用 Debug 模式编译程序...\n"); #else printf("正在使用 Release 模式编译程序...\n"); #endif system("pause"); return 0;}
当以Debug模式编译程序时,宏_DEBUG会被定义,预处器会保留第5行代码,删除第7行代码。反之会删除第5行,保留第7行。
#ifndef 命令:
#ifndef 命令的格式为:
#ifndef 宏名 程序段1#else 程序段2#endif
与#ifdef相比,仅仅是将#ifdef改为了#ifndef。它的意思是,如果当前的宏未被定义,则对“程序段1”进行编译,否则对“程序段2”进行编译,这与#ifdef的功能正好相反。
区别:
最后需要注意的是,#if后面跟的是“整型常量表达式”,而#ifdef和#ifndef后面跟的只能是一个宏名,不能是其他的。
例如,下面的形式只能用于#if:
#include#define NUM 10int main(){ #if NUM == 10 || NUM == 20 printf("NUM: %d\n", NUM); #else printf("NUM Error\n"); #endif return 0;}
运行结果:
NUM: 10
再如,两个宏都存在时编译代码A,否则编译代码B:
#include#define NUM1 10#define NUM2 20int main(){ #if (defined NUM1 && defined NUM2) //代码A printf("NUM1: %d, NUM2: %d\n", NUM1, NUM2); #else //代码B printf("Error\n"); #endif return 0;}
运行结果:
NUM1: 10, NUM2: 20
#ifdef 可以认为是#if defined的缩写。