面试官:请简单描述下编译器将C语言从源代码到可执行文件的过程。
应聘者:呃……就是……在IDE里写代码,然后点编译啊……
面试官:那你知道预处理命令这个东西吗,平时用过有哪些?
应聘者:这个我懂,不就是宏定义那些嘛,我平时用#define来定义某些数值,还有用#ifdef来做选择性编译,这些挺简单的啊。
面试官:嗯,好,今天先聊到这,回去等通知吧。
不知道这个问题的,有可能你一直都是用IDE做开发,而没思考过IDE里面经历了什么。如果你用过GCC,你应该大概知道这是一个怎样的过程:
这个过程里面有个Pre-processing,很不起眼,但是非常关键,如果用得好,你的代码也会变得很奇妙。
以下是基于C99标准,总结C语言预处理的知识点以及其相关用法和问题剖析。
注:本文所有案例测试都是基于Windows上的GCC(gccversion6.3.0(MinGW.orgGCC-6.3.0-1))
抛开大脑里零零散散的几个概念,我们直接参考C99标准(ISO/IEC:(E)),简单汇总有以下命令或用法:
分类命令解释简单示例01.条件包含Conditionalinclusion#if,#else,#elif,#endif,#ifdef,#ifndef,#undef即平时理解的条件编译#ifdefidentifier02.源文件包含Sourcefileinclusion#include头文件/源文件包含#includeh-char-sequencenew-line03.宏替换Macroreplacement#define,#,##宏替换A##B04.行控制Linecontrol#line行控制。一般很少用#linedigit-sequencenew-line05.错误指示Errordirective#error出错指示。做预处理检查,可以输出错误提示信息。#errorpp-tokensoptnew-line06.空指令Nulldirective#空指。看起来没什么用令#new-line07.预定义宏名Predefinedmacronames__DATE__,__FILE__,__LINE__,__STDC__,__TIME__预定义宏名08.Pragma命令/操作Pragmadirective/operator_Pragma,#pragmapragma指令#pragmalistingon"..\listing.dir"以上内容,大部分都很常见,如果要说用得好,那是个艺术活。
1.语法形式预处理有以下语法形式:
preprocessing-file:
groupoptgroup:
group-partgroupgroup-part
group-part:
if-section
control-line
text-line
#non-directive
if-section:
if-groupelif-groupsoptelse-groupoptendif-line
if-group:
#ifconstant-expressionnew-linegroupopt
#ifdefidentifiernew-linegroupopt
#ifndefidentifiernew-linegroupopt
elif-groups:
elif-group
elif-groupselif-group
elif-group:
#elifconstant-expressionnew-linegroupopt
else-group:
#elsenew-linegroupoptendif-line: #endifnew-linecontrol-line: #includepp-tokensnew-line #defineidentifierreplacement-listnew-line #defineidentifierlparenidentifier-listopt) replacement-listnew-line #defineidentifierlparen...)replacement-listnew-line #defineidentifierlparenidentifier-list,...) replacement-listnew-line #undefidentifiernew-line #linepp-tokensnew-line #errorpp-tokensoptnew-line #pragmapp-tokensoptnew-line #new-linetext-line: pp-tokensoptnew-linenon-directive: pp-tokensnew-linelparen: a(characternotimmediatelyprecededbywhite-spacereplacement-list: pp-tokensoptpp-tokens: preprocessing-token pp-tokenspreprocessing-tokennew-line: thenew-linecharacter
2.描述预处理指令由一系列预处理令牌组成,这些预处理令牌以#预处理令牌开头,它是源文件中的第一个字符或紧跟着包含至少一个换行符的空白,并在下一个换行符结束。
文本行不要以#开头,非指令内容也不要用“语法形式”中的内容作为开头
3.约束在预处理指令中的预处理标记之间(从引入#预处理标记之后到结束换行符之前),唯一出现的空白字符是空格和水平制表符(包括替换了注释或可能的空格)
/*