目录
承接95.【C语言】解析预处理(3)文章
5.条件编译
即选择性编译,某些情况下需要编译,而某些情况下不需要编译,常见的是调试代码
#ifdef
#include <stdio.h>
#define __DEBUG__
int main()
{
int arr[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("arr[%d]=%d\n", i, arr[i]);//检查是否正常赋值
#endif // __DEBUG__
}
return 0;
}
解释:#ifdef __DEBUG__ 表示是否定义了__DEBUG__,#endif表示结束一个条件编译块
如果有#define __DEBUG__ 则执行条件编译,否则不执行
其他条件编译指令
#if
#if 常量表达式
//...
#endif
例如微软提供的stdio.h中有如下代码
#if __STDC_WANT_SECURE_LIB__
#define L_tmpnam_s L_tmpnam
#endif
解释: 如果__STDC_WANT_SECURE_LIB__值为真,则定义#define L_tmpnam_s L_tmpnam
多个分支的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
例如某项目下有如下代码(参见)
#ifdef ENABLE_NLS
#include <libintl.h>
#else
#define gettext(x) (x)
#endif
如果定义了ENABLE_NLS,则包含libintl.h,否则定义#define gettext(x) (x)
判断是否被定义
#if defined(symbol)等价写法为#ifdef symbol
#if !defined(symbol)等价写法为#ifndef symbol
例如微软的<stdlib.h>中有如下代码
#ifndef _countof
#define _countof __crt_countof
#endif
(#ifndef全称if not define)
解释:如果没有定义 _countof,则定义#define_countof __crt_countof
嵌套指令
例如某项目下有如下代码(参见GitHub mir/mir.c)
#if defined(__x86_64__) || defined(_M_AMD64)
#include "mir-x86_64.c"
#elif defined(__aarch64__)
#include "mir-aarch64.c"
#elif defined(__PPC64__)
#include "mir-ppc64.c"
#elif defined(__s390x__)
#include "mir-s390x.c"
//......
#else
#error "undefined or unsupported generation target"
#endif
defined()用于检查某个宏是否已经被定义
上段代码是根据目标系统的处理器架构包含不同的源文件
#if defined(__x86_64__) || defined(_M_AMD64) 即如果是x86_64架构,则包含mir-x86_64.c文件
#elif defined(__aarch64__) 是否是aarch64架构? 如果是则包含mir-aarch64.c
......(后面的类似不分析)
6.头文件的包含方式
本地文件包含
#include "xxxxxx" //使用双引号
先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在
标准位置查找头文件
标准位置:
Linux: /usr/include
VS2022: 默认路径为C:\Program Files (x86)\Windows Kits\10\Include
库文件包含
#include <xxxxxx> //使用尖括号
直接去标准路径下去查找,如果找不到就提示编译错误
不建议使用双引号去包含库文件,否则消耗库文件的寻找时间
嵌套文件包含
问题:头文件的重复包含
例如:test.h中写入:
void test_func();
main.c写入:
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
return 0;
}
Linux下编译头文件会包含5次,文件体积变大
解决问题:避免头文件的重复包含
方法1:#pragma once
即只包含一次,将#pragma once写入头文件中,再预处理生成i文件,发现test.h只包含一次
方法2:#ifndef、#define和#endif
格式:
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__
例如test.c包含两次test.h,展开头文件后为
#ifndef __TEST_H__
#define __TEST_H__
void test_func();
#endif //__TEST_H__
#ifndef __TEST_H__
#define __TEST_H__
void test_func();
#endif //__TEST_H__
int main()
{
return 0;
}
将代码粘贴到VS上看看,会发现字体的颜色深浅不同
画图分析
7.其他预处理指令
#error
作用:预处理到#error命令时将停止编译并输出用户自定义的错误消息
例如某项目中有如下代码(参见GitHub ruby/st.c)
#if MINIMAL_POWER2 < 2
#error "MINIMAL_POWER2 should be >= 2"
#endif
将上方的代码添加到自己写的c文件中,调试看看
#define MINIMAL_POWER2 1
#if MINIMAL_POWER2 < 2
#error "MINIMAL_POWER2 should be >= 2"
#endif
int main()
{
return 0;
}
VS上的编译结果: 输出自定义的错误信息