程序环境和预处理
-
程序的翻译环境
-
程序的执行环境
-
详解:C语言程序的编译+链接预定义符号介绍
-
预处理指令#define
一.程序的翻译环境
在ANSI C的任何一种实现中,存在两个不同的环境。
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
注意:机器指令也就是二进制识别
第2种是执行环境,它用于实际执行代码。
在企业中一个项目组有多名成员完成项目,各写各的.c文件最后通过编译器和连接器完成
我们的项目;
每一个源文件都需要通过编译器翻译成目标文件.obj;所有的.obj文件和链接库共同协作
生成可执行程序.exe
编译器-cl.exe;链接器-link.exe;
组成一个程序的每个源文件通过编译过程分别转换成目标代码(objec code)。每个目标文件由链接器 捆绑在一起,形咸一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序
编译过程包含三个部分:预编译,编译,汇编;
我们的vs编译器属于集成开发环境,我们在编译时看不到具体细节
在gcc环境下可以了解编译的细节处理
1.预处理
gcc test.c -E(预处理指令) -o(输出) test.i(预处理后生成的文件)
1.头文件的包含
#include包含于程序test.c中预处理文件test.i中将头文件中的内容调出来;
2.define定义符号的替换删除定义的符号
3.注释删除
注释是写给程序员看的,编译器对语法规则了如指掌,预处理会删除注释内容;
4.预处理阶段是对文本进行操作;
2.编译
gcc test. i -S(gcc环境下对test.i文件进行编译处理就结束)
生成了test.s
把C语言代码转化成汇编代码
语法分析
词法分析
符号汇总(符号汇总只统计全局符号,函数中的局部变量不会统计)
语义分析
3.汇编
gcc test. s -c
生成了test. o(目标文件)
把汇编代码转换成二进制指令
形成符号表
在编译阶段进行符号汇总后,在汇编阶段对这些符号编号地址;
4.链接
合并段表
符号表的合并和重定位
add.o
test.o链接库
在第一个.c文件中写的函数在另一个.c文件中使用
在编译期间系统会对每一个.c文件编译,对全局字符汇总统计出现两个add字符名称它们分别被赋予不同地址;
在链接时会对重复的符号表进行重定位取两者之间的有效地址;有效地址的判断取决于编译器;
二.运行环境
程序执行的过程:
1.程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2.程序的执行便开始。接着便调用main函数。
3.开始执行程序代码。这个时候程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4.终止程序。正常终止main函数;也有可能是意外终止。
三.预处理详解
1.预定义符号
__FILE__:进行编译的源文件
__LINE__:文件当前的行号
__DATE__:文件被编译的日期
__TIME__:文件被编译的时间
__STDC__: 如果编译器遵循ANSI c,其值为1,否则未定义
2.预定义符号的使用
当我们想知道打印的数据是在那个文件里的可以用__FILE__或者其他的信息可以用对对应的预定义符号;
通常可以在我们写日志时应用;
3.预处理指令#define
define定义的内容可以是多样的可以是整形也可以是字符串甚至可以是一段代码;
define定义的后面尽量不要加分号;如果:#define MAX 1000;
MAX在预处理之后会被替换成 1000; 不易操作
#define MAX1000
#define reg register
为register这个关键字,创建一个简短的名字
#define do_foreverfor( ; ; )
用更形象的符号来替换一种实现
#define CASE break ; case
在写case语句的时候自动把 break写上。
当一段代码过长想要分多行写,可以加续行符'\'操作;
不加续行符程序会报错;续行符实际上转义的是回车;