TheCsourcefileisprocessedbythecompilerasifthefollowingphasestakeplace,inthisexactorder。Actualimplementationmaycombinetheseactionsorprocessthemdifferentlyaslongasthebehavioristhesame。 编译器对C源文件进行处理,就好像以下阶段按照这个确切的顺序进行一样。只要行为相同,实际实现可能会组合这些操作或以不同的方式处理它们。Phase1字符映射 Theinpidualbytesofthesourcecodefile(whichisgenerallyatextfileinsomemultibyteencodingsuchasUTF8)aremapped,inimplementationdefinedmanner,tothecharactersofthesourcecharacterset。Inparticular,OSdependentendoflineindicatorsarereplacedbynewlinecharacters。 源代码文件的各个字节(通常是一些多字节编码(如UTF8)的文本文件)以实现定义的方式映射到源字符集的字符。特别是,依赖操作系统的行尾指示符被换行符所取代。(不同的字符集对同一个汉字的编码可能是不同的。) Thesourcecharactersetisamultibytecharactersetwhichincludesthebasicsourcecharactersetasasinglebytesubset,consistingofthefollowing96characters: 源字符集是一个多字节字符集,包括作为单字节子集的基本源字符集,由以下96个字符组成:a)5whitespacecharacters(space,horizontaltab,verticaltab,formfeed,newline) 5个空格字符(空格、水平制表符、垂直制表符、换页符、换行符) b)10digitcharactersfrom0to9 从0到9的10位数字字符 c)52lettersfromatozandfromAtoZ 从a到z以及从a到z的52个字母 d)29punctuationcharacters:{}〔〕():;。?!, 29个标点符号:{}〔〕35;():;。?!, Trigraphsequencesarereplacedbycorrespondingsinglecharacterrepresentations。 三角图序列由相应的单字符表示代替。Phase2物理换行替换为逻辑换行 1)Wheneverbackslashappearsattheendofaline(immediatelyfollowedbythenewlinecharacter),bothbackslashandnewlinearedeleted,combiningtwophysicalsourcelinesintoonelogicalsourceline。Thisisasinglepassoperation:alineendingintwobackslashesfollowedbyanemptylinedoesnotcombinethreelinesintoone。 每当反斜杠出现在行尾(紧跟着换行符),反斜杠和换行符都会被删除,将两个物理源行合并为一个逻辑源行。这是一个单程操作:一条以两个反斜杠结尾并后跟空行的行不会将三行合并为一行。 2)Ifanonemptysourcefiledoesnotendwithanewlinecharacterafterthisstep(whetherithadnonewlineoriginally,oritendedwithabackslash),thebehaviorisundefined。 如果非空源文件在此步骤之后没有以换行符结尾(无论它最初是否没有换行符,或者以反斜杠结尾),则行为未定义。Phase3单条注释替换为一个空格 3。1Thesourcefileisdecomposedintocomments,sequencesofwhitespacecharacters(space,horizontaltab,newline,verticaltab,andformfeed),andpreprocessingtokens,whicharethefollowing 源文件分解为注释、空格字符序列(空格、水平制表符、新行、垂直制表符和表单提要)和预处理标记,如下所示a)headernames:stdio。hormyfile。h b)identifiers c)preprocessingnumbers,whichcoverintegerconstantsandfloatingconstants,butalsocoversomeinvalidtokenssuchas1。。E3。fooor0JBK 预处理数字,包括整数常量和浮点常量,但也包括一些无效标记,如1。。E3。foo或0JBK d)characterconstantsandstringliterals 字符常量和字符串文字 e)operatorsandpunctuators,suchas,,,or。 运算符和标点符号,如、、或。 f)inpidualnonwhitespacecharactersthatdonotfitinanyothercategory 不适用于任何其他类别的单个非空白字符 3。2Eachcommentisreplacedbyonespacecharacter 每个注释都替换为一个空格字符 3。3Newlinesarekept,anditsimplementationdefinedwhethernonnewlinewhitespacesequencesmaybecollapsedintosinglespacecharacters。 保留换行符,它的实现定义了非换行符空格序列是否可以折叠为单个空格字符。 Iftheinputhasbeenparsedintopreprocessingtokensuptoagivencharacter,thenextpreprocessingtokenisgenerallytakentobethelongestsequenceofcharactersthatcouldconstituteapreprocessingtoken,evenifthatwouldcausesubsequentanalysistofail。Thisiscommonlyknownasmaximalmunch。 如果输入已被解析为预处理标记(最多可达给定字符),则下一个预处理标记通常被视为可能构成预处理标记的最长字符序列,即使这会导致后续分析失败。这通常被称为贪婪原则(最大吞噬)。intfoo1;intbar0xEerror:invalidpreprocessingnumber0xEfoointbaz0xEOKOK:OK:error:barbaz,notbarbaz。 Thesoleexceptiontothemaximalmunchruleis: 贪婪规则(最大吞噬)的唯一例外是: Headernamepreprocessingtokensareonlyformedwithinaincludedirectiveandinimplementationdefinedlocationswithinapragmadirective。 头文件预处理标记仅在include指令内和pragma指令内实现定义的位置中形成。defineMACRO11defineMACRO22defineMACRO33defineMACROEXPR(MACRO1MACRO2MACRO3)OK:MACRO2isnotaheadernamePhase4预处理 1)Preprocessorisexecuted。 执行预处理器。 2)Eachfileintroducedwiththeincludedirectivegoesthroughphases1through4,recursively。 使用include指令引入的每个文件都会递归地经历阶段1到4。 3)Attheendofthisphase,allpreprocessordirectivesareremovedfromthesource。 在此阶段结束时,将从源代码中删除所有预处理器指令。Phase5字符集转换 1)Allcharactersandescapesequencesincharacterconstantsandstringliteralsareconvertedfromsourcecharactersettoexecutioncharacterset(whichmaybeamultibytecharactersetsuchasUTF8,aslongasall96charactersfromthebasicsourcecharactersetlistedinphase1havesinglebyterepresentations)。Ifthecharacterspecifiedbyanescapesequenceisntamemberoftheexecutioncharacterset,theresultisimplementationdefined,butisguaranteedtonotbeanull(wide)character。 字符常量和字符串文字中的所有字符和转义序列都从源字符集转换为执行字符集(可以是多字节字符集,如UTF8,只要阶段1中列出的基本源字符集中的所有96个字符都具有单字节表示)。如果转义序列指定的字符不是执行字符集的成员,则结果是实现定义的,但保证不是空(宽)字符。当源文件被转换为可执行程序以后,这些由字符所组成的源代码,都将被替换为实现了相同功能的机器指令。但是,源文件中的字符串、字符常量等信息文本,并不会被替换为相应的机器指令。因为,它们并不对应某个功能,它们一般是用来打印和输出、传输。所以,它们在可执行文件(程序)中存储的仍然是其所对应的字符编码。 接下来的问题是:字符串、字符常量等信息文本在可执行文件中是按照哪种字符编码来存储的?这是由gcc来决定的:Linux下gcc默认使用UTF8来存储这些信息文本到可执行文件中。 Note:theconversionperformedatthisstagecanbecontrolledbycommandlineoptionsinsomeimplementations:gccandclangusefinputcharsettospecifytheencodingofthesourcecharacterset,fexeccharsetandfwideexeccharsettospecifytheencodingsoftheexecutioncharactersetinthestringliteralsandcharacterconstantsthatdonthaveanencodingprefix(sinceC11)。 注意:在某些实现中,此阶段执行的转换可以由命令行选项控制:gcc和clang使用finputcharset指定源字符集的编码,fexeccharset和fwideexeccharset指定没有编码前缀的字符串文字和字符常量中执行字符集的编码(自C11起)。Phase6相邻的字符串字面量串联到一起 Adjacentstringliteralsareconcatenated。 相邻的字符串文字是串联的。 从ANSIC标准起,如果字符串字面量之间没有间隔,或者用空白字符分隔,C会将其视为串联起来的字符串字面量。例如:chargreeting〔20〕Hello,andhowareyoutoday!; 与下面的代码等价:chargreeting〔5O〕Hello,andhowareyoutoday!;Phase7编译 Compilationtakesplace:thetokensaresyntacticallyandsemanticallyanalyzedandtranslatedasatranslationunit。 编译发生:标记在语法和语义上进行分析,并作为翻译单元进行翻译。Phase8链接 Linkingtakesplace:Translationunitsandlibrarycomponentsneededtosatisfyexternalreferencesarecollectedintoaprogramimagewhichcontainsinformationneededforexecutioninitsexecutionenvironment(theOS)。 链接发生:满足外部引用所需的翻译单元和库组件被收集到一个程序映像中,其中包含在其执行环境(OS)中执行所需的信息。 End