C\C++ 编译器如何处理源文件

                                                C语言基础知识

一、编译器如何处理C源文件(source file)。

1)、以某种编码方式替换源文件中的字符,例如:用换行符替换OS里的行尾指示符。

不同OS里的行尾指示符是不同的,例如Windows 是\r\n,UNIX 是 \r,MAC OS 是\n

如:在8086汇编中,我们在DOS下编写输出程序经常需要执行 向内存中添加 0AH,0DH。

用来进行换行操作,其中0AH转换为ASCII码其实现的功能就是\r,0DH实现的功能就是\n。

\r 为 回车 在C程序中,如果输出字符中使用了\r,其效果为光标移动到----本行开始的位置。

\n 为换行 意思为光标移动到下一行的

2)、有时候我们会因为一条语句需要进行多行去书写,那么就会在语句中间添加一个 \ 然后进行换行继续编写,编译器就会把这个\去掉并且去掉换行符,并且将下一行与本行连接起来,实现一个逻辑行。

扫描二维码关注公众号,回复: 1760922 查看本文章

3)、将源文件分解为注释部分、空白字符序列、一些预处理记号。

预处理记号:

1、头文件 例如 <stdio.h> 或者 “ myheader.h”

2、字面值常量

3、标识符

4、预处理 常量

5、运算符 与 标点。

6、其它非空白字符。

其实可以把C语言的组成部分看成是一些记号的集合,例如:

printf("Hello World. %d",var_1);

printf (标识符) ( "Hello World" (字符串字面量) , var_1(标识符) ) ; 其它为标点。

用一个空格替换一段注释。

保持换行符。

编译器在处理我们的源文件中,会尽最大处理预处理记号。

例如

 
 
int var_1=1;
int var_2=0xE+var_1;   //WRONG
int var_3=0xE + var_1;

当处理第二条语句中, 会尽最大可能处理这些记号,那么0xE+var_1会被处理成一个整数常量,可是这个常量是非法的。所以会出现错误。而第二个会被分解成 0xE 、+ 和 var_1 三部分,所以它是正确的。在一些编辑器中当我们换行时,会自动添加空格在不同预处理记号之间(例如:Visual Studio )。

但是在头文件中可避免这中意外的发生,因为头文件只在#include 与 #pragma 中会发生定义行为。

例如:

 
 
#define DATA (FF <TEST> VV)

4)、

1、进行预处理(下面会详细介绍什么是预处理)

2、#include所调用的文件执行上面所有操作。

3、完成这些操作后文件移除所预处理指令。

5)、字符常量与字符串常量和转移序列转换成可执行字符。

6)、连接相邻的字符串字面量。

7)、编译:分析语义和语法翻译成翻译单元。

8)、进行链接:将翻译单元和外部引用单元进行连接成OS可执行文件。

二、预处理器

baidu 预处理器是在真正的编译开始之前由编译器调用的独立程序。预处理器可以删除注释、包含其他文件以及执行宏(宏macro是一段重复文字的简短描写)替代。

wiki A common example from computer programming is the processing performed on source code before the next step of compilation. In some computer languages (e.g., C and PL/I) there is a phase of translation known as preprocessing. It can also include macro processing, file inclusion and language extensions.

预处理指令

条件编译

 
 
#ifdef       //对某个macro进行判断,如果定义了执行相应代码块,如果没有执行下一个条件预处理
#ifndef     //与ifdef相反
#endif          //这个条件预处理块终止符
#if         //不是针对define 而是一个表达式
/*
    #if !defined(NAME) 
    #define COLOR "Blue"
    #else
    #define COLOR "Red"
*/
#elif       
#else

宏替换

我们调用#define DEMO " This is a demo"

在我们的程序中每当遇见DEMO 就会替换成"This is a demo "

而#undef意思为取消我们之前定义的宏

包含其它文件

则遇见#include <head_file>或者 #include" myhead.h" 会查找该文件的位置并且放入源文件相应指令后面的位置。

1、#include<> 其搜索路径为标准库目录

2、#include" " 其第一次搜索目录为当前源文件目录下,如果没有搜索到,再去搜索标准库目录

错误指令

若使用#error 则会引发错误,是程序不能继续编译。并且告诉为什么。

例如:

 
 
#ifndef DEMO
#define DEMO 22
#endif
#include<stdio.h>
#if DEMO==22
#error "Sorry!"
#endif
int main()
{
  printf("Hello World!\n");
  return 0;
}

RUN:

 
 
xiandonghua@HappyDay:~/c$ gcc demo.c -o demo 
demo.c:8:2: error: #error "Sorry!"
 #error "Sorry!"
  ^

如果我们只把 #if DEMO == 22 改成 #if DEMO == 33 其它代码不变。

RUN:

 
 
xiandonghua@HappyDay:~/c$ gcc demo.c -o demo 
xiandonghua@HappyDay:~/c$ ./demo 
Hello World!

实现定义行为#pragma

使用#pragma 控制编译器的行为,例如 禁用编译器警告和更改对其要求。

相对其他预处理,pragma想对比较复杂,它的语法:

 
 
#pragma parament  //parament 为参数

一般使用的指令

 
 
#pragma message("This is a demo") //在编译过程中会打印字符内容
#pragma code_seg()     //设置程序中函数代码存放的代码段(code segment).
#pragma once            //源文件中调用的头文件有且仅只调用一次,因为有时候有的头文件会被间接重复调用
#pragma hdrstop         //表示到目前为止之后的头文件不再编译
#pragma warning(disable:1234)  //不再显示为1234序号的警告,VS 里会有这种序号,但GCC 目前没有找到

文件名和行信息 (...........)

使用#line 行号 或者 #line 行号 文件名

如果在某一位置使用#line 999 那么它的下一行行号为999,之后每行+1。

如果在某一位置使用#line 999 同上另外编译器会提示你的文件名不再是你运行的文件名。(可执行文件名没有更改,只是编译器所报的文件名更改)


                                                                学习,学一点,是一点。

猜你喜欢

转载自blog.csdn.net/arctic_fox_cn/article/details/80784911