0%

C语言预处理

ANSI C标准

ANSI C是美国国家标准协会(ANSI)对C语言发布的标准。使用C的软件开发者被鼓励遵循ANSI C文档的要求,因为它鼓励使用跨平台的代码。

发展过程中产生了C89、C90、C99、C11四套标准,最早的C89在1983年创立,C90是1990年创立的ANSI C标准(带有一些小改动),C99在2000年3月创立,C11在2011年12月创立。

C预处理器

指令 描述
#define 定义宏
#include 包含一个源代码文件
#undef 取消已定义的宏
#ifdef 如果宏已经定义,则返回真
#ifndef 如果宏没有定义,则返回真
#if 如果给定条件为真,则编译下面代码
#else #if 的替代方案
#elif 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
#endif 结束一个 #if……#else 条件编译块
#error 当遇到标准错误时,输出错误消息
#pragma 使用标准化方法,向编译器发布特殊的命令到编译器中

预定义宏

ANSI C 定义了许多宏。在编程中可以使用这些宏,但是不能直接修改这些预定义的宏。

描述
__DATE__ 当前日期,一个以 “MMM DD YYYY” 格式表示的字符常量。
__TIME__ 当前时间,一个以 “HH:MM:SS” 格式表示的字符常量。
__FILE__ 这会包含当前文件名,一个字符串常量。
__LINE__ 这会包含当前行号,一个十进制常量。
__STDC__ 当编译器以 ANSI 标准编译时,则定义为 1。

#pragma

#pragma指令的作用是:用于指定计算机或操作系统特定的编译器功能。C 和 C++ 的每个实现均支持某些对其主机或操作系统唯一的功能。 例如,某些程序必须对将数据放入的内存区域进行准确的控制或控制某些函数接收参数的方式。 在保留与 C 和 C++ 语言的总体兼容性的同时,#pragma 指令使每个编译器均能够提供特定于计算机和操作系统的功能。

根据定义,#pragma指令是计算机或操作系统特定的,并且通常对于每个编译器而言都有所不同。 #pragma指令可用于条件语句以提供新的预处理器功能,或为编译器提供实现所定义的信息。

#pragma pack([ show ] | [ push | pop ] [, identifier ] , n),用于内存对齐。
#pragma message(messageString),用于不中断编译的情况下,发送一个字符串文字量到标准输出。

编译器可识别的指令还有很多。

##和…

## 起连接字符串的作用,用于把参数宏中的“形参”与其它没有天然分割的内容粘连在一起。
例如:#define def_u32_array(__name, __size) uint32_t array_##__name[__size];
def_u32_array(sample_buffer, 64),宏展开后为:uint32_t array_sample_buffer[64];

... 是ANSI-C99标准引入的另外一个参数宏扩展,“可变参数宏”,其实就是将__VA_ARGS__替换为…中的值。
例如:#define log_info(__STRING, ...) printf(__STRING, __VA_ARGS__)
log_info("Count:%d", total_cycle_cnt);,宏展开后:printf("Count:%d", total_cycle_cnt);
log_info("-----------------\r\n");,宏展开后:printf("-----------------\r\n",);,…无参数,__VA_ARGS__为空,但是宏展开后仍有逗号。

逗号后无内容可能会产生个warning,想解决逗号问题,可以##和…一起使用。
例如:\#define log_info(__STRING, ...) printf(__STRING,##__VA_ARGS__)
log_info("-----------------\r\n");,宏展开后:printf("-----------------\r\n");

…初始化数组

int a[5] = {[0...2] = 1, [3...4] = 2};使数组a[0]~a[2] = 1, a[3]和a[4] = 2。

这种写法只可以在gcc编译C的情况下使用,gcc编译c++也不行。