我是靠谱客的博主 畅快心情,最近开发中收集的这篇文章主要介绍关于C之条件编译指令#undef、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

条件编译:可以使用其他指令创建条件编译(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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(79)

评论列表共有 0 条评论

立即
投稿
返回
顶部