概述
条件编译:可以使用其他指令创建条件编译(conditinal compilation)。也就是说,可以使用这些指令告诉编译器根据编译时的条件执行或忽略信息(或代码)块。
1.#ifdef、#else和#endif指令:
#ifdef MAVIS
#include "horse.h" // 如果已经用#define定义了 MAVIS,则执行下面的指令
#define STABLES 5
#else
#include "cow.h" //如果没有用#define定义 MAVIS,则执行下面的指令
#define STABLES 15
#endif
可以在程序代码中直接使用这些指令:
#include <stdio.h>
#define JUST_CHECKING
#define LIMIT 4
int main(void) {
int i;
int total = 0;
for (i = 1; i <= LIMIT; i++) {
total += 2 * i*i + 1;
#ifdef JUST_CHECKING
printf("i=%d, running total = %dn", i, total);
#endif
}
printf("Grand total = %dn", total);
return 0;
}
i=1, running total = 3
i=2, running total = 12
i=3, running total = 31
i=4, running total = 64
Grand total = 64
可以用这种方法在调试程序。定义JUST_CHECKING并合理使用#ifdef,编译器将执行用于调试的程序代码,打印中间值。调试结束后,可移除/注释掉JUST_CHECKING定义并重新编译。如果以后还需要使用这些信息,重新插入/解注释定义即可。这样做省去了再次输入额外打印语句的麻烦。#ifdef还可用于根据不同的C实现选择合适的代码块。
2.#ifndef指令:
#ifndef指令与#ifdef指令的用法类似,也可以和#else、#endif一起使用,但是它们的逻辑相反。#ifndef指令防止相同的宏被重复定义。
/* arrays.h */
#ifndef SIZE
#define SIZE 100
#endif
// names.h -- 避免重复包含
#ifndef NAMES_H_
#define NAMES_H_
// 明示常量
#define SLEN 32
// 结构声明
struct names_st{
char first[SLEN];
char last[SLEN];
};
// 类型定义
typedef struct names_st names;
// 函数原型
void get_names(names *);
void show_names(const names *);
char * s_gets(char * st, int n);
#endif
3.#if和#elif指令:
#if defined (IBMPC)
#include "ibmpc.h"
#elif defined (VAX)
#include "vax.h"
#elif defined (MAC)
#include "mac.h"
#else
#include "general.h"
#endif
如果在VAX机上运行这几行代码,那么应该在文件前面用下面的代码定义VAX:
#define VAX
C标准规定了一些预定义宏:
#include <stdio.h>
void why_me();
int main() {
printf("The file is %s.n", __FILE__);
printf("The date is %s.n", __DATE__);
printf("The time is %s.n", __TIME__);
printf("The version is %ld.n", __STDC_VERSION__);// Win7 x86 VS2019下"undefinded".
printf("This is line %d.n", __LINE__);
printf("This function is %sn", __func__);
why_me();
return 0;
}
void why_me() {
printf("This function is %sn", __func__);
printf("This is line %d.n", __LINE__);
}
The file is /Volumes/Data/workplace/c_workplace/XcodeCpp/XcodeCpp/hello.c.
The date is Nov 9 2019.
The time is 23:11:51.
The version is 201112.
This is line 8.
This function is main
This function is why_me
This is line 15.
4.#line和#error指令:
#line指令重置_ _LINE_ _和_ _FILE_ _宏报告的行号和文件名。
#line 1000 // 把当前行号重置为1000
#line 10 "cool.c" // 把行号重置为10,把文件名重置为cool.c
#error 指令让预处理器发出一条错误消息,该消息包含指令中的文本。如果可能的话,编译过程应该中断。
#if _ _STDC_VERSION_ _ != 201112L
#error Not C11
#endif
$ gcc newish.c
newish.c:14:2: error: #error Not C11
$ gcc -std=c11 newish.c
$
5.#pragma指令:
在现在的编译器中,可以通过命令行参数或IDE菜单修改编译器的一些设置。#pragma把编译器指令放入源代码中。例如,在开发C99时,标准被称为C9X,可以使用下面的编译指示(pragma)让编译器支持C9X:
#pragma c9x on
C99还提供_Pragma预处理器运算符,该运算符把字符串转换成普通的编译指示。例如:
_Pragma("nonstandardtreatmenttypeB on")
等价于下面的指令:
#pragma nonstandardtreatmenttypeB on
_Pragma运算符还完成了“解字符串”的工作,即把字符串中的转义序列转换成它所代表的字符。如:
_Pragma("use_bool "true "false")
变成了:
#pragma use_bool "true "false
由于_Pragma运算符不使用#符号,所以可以把它作为宏展开的一部分:
#define PRAGMA(X) _Pragma(#X)
#define LIMRG(X) PRAGMA(STDC CX_LIMITED_RANGE X)
然后,可以使用类似下面的代码:
LIMRG ( ON )
顺带一提,上面代码看上去没问题,但实际无法运行:问题在于第二条#define LIMGR(X)...代码依赖字符串的串联功能,而预处理过程完成之后才会串联字符串。
#pragma once
为了避免同一个头文件被包含(include)多次,C/C++中有两种宏实现方式:一种是#ifndef方式;另一种是#pragma once方式。
在能够支持这两种方式的编译器上,二者并没有太大的区别。但两者仍然有一些细微的区别。两者的使用方式有何区别?示例代码如下:
方式一:
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
... ... // 声明、定义语句
#endif
方式二:
#pragma once
... ... // 声明、定义语句
(1)#ifndef
#ifndef的方式受C/C++语言标准支持。它不仅可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不会被不小心同时包含。
(2)#pragma once
#pragma once一般由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。
最后
以上就是畅快心情为你收集整理的关于C之条件编译指令#undef、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma的全部内容,希望文章能够帮你解决关于C之条件编译指令#undef、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复