5--函数和编译预处理
- 格式:doc
- 大小:57.00 KB
- 文档页数:11
C 语言中级培训预处理的概念编译前编译预处理器语言中,以“#”开头的语句统称为编译预处理命令。
以“#”开始,末尾这些命令必须在一行的开头以“#”开始,末尾不加分号,并且每条命令独占一行不加分号,并且每条命令独占一行,以区别于一为什么要用” 预处理”最小原则丁”的方式,由语言之外的预处理命令或函数提供。
就连处理预处理命令的预处理器C语言的预处理命令“预处理”前的预处理//有的系统是/ ,如VC++什么是宏#define PI (3.1415926)宏定义指令宏名字符串宏定义为什么要用宏定义-文字名称比数字要容易理解得多,一个好的宏名可以望文知义。
120使用宏的弊端:使用宏定义时需要注意的要点:宏替换的弊端:#define PF(x)x*x()()()/*#define PF(x)(x)*(x)*//*#define PF(x)((x)*(x))*/main()注意替换时不求值,{只是字符串的原样替换int a=2,b=3,c;c=PF(a+b)/PF(a+1);printf("\nc=%d",c);}按第一种宏定义:c=a+b*a+b/a+1*a+1;按第二种宏定义:()()()();c=(a+b)*(a+b)/(a+1)*(a+1)按第三种宏定义:c=((a+b)*(a+b))/((a+1)*(a+1));多用括号就万事大吉了吗?2:在定义宏时不要为宏加分号。
#define assert(e)\续行符#define assert(e) \宏定义实例——无参宏定义举例宏定义实例——带参数的宏定义举例宏定义实例——用宏定义构建机制#ifdef AFXDLL #ifdef _AFXDLL{0000AfxSig end(AFX PMSG)0}\ {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \函数调用和宏定义的区别宏定义和类型定义的区别struct student*struct student *st uct stude t请分析下面语句的含义(*((UINT1*)(_data_)))定义了一个带参宏,它能将参数强转成无符号字符类型的地址,再将该地址中的值取出。
c++编译顺序c++编译顺序是指c++程序从源代码到可执行文件的转换过程中,各个源文件和目标文件的生成和处理的先后顺序。
c++程序一般由多个源文件(.cpp)和头文件(.h)组成,每个源文件都需要经过预处理(preprocess),编译(compile),汇编(assemble)和链接(link)四个阶段,才能最终生成可执行文件(.exe)。
不同的源文件之间可能存在依赖关系,比如一个源文件调用了另一个源文件中定义的函数或变量,或者一个源文件包含了另一个头文件中声明的内容。
因此,c++编译顺序需要考虑这些依赖关系,保证每个源文件在被处理之前,它所依赖的其他源文件或头文件已经被正确地处理过。
原理c++编译是基于c++程序的运行原理和编译器的工作原理。
c++程序的运行原理是基于计算机硬件和操作系统的,计算机只能执行机器语言指令,而操作系统负责加载可执行文件到内存,并调用入口函数开始执行。
因此,c++程序需要将人类可读的高级语言代码转换为机器可执行的二进制代码,并且按照操作系统规定的格式组织成可执行文件。
这个转换过程就是由编译器完成的。
编译器是一种软件,它可以将一种语言(源语言)翻译成另一种语言(目标语言)。
为了提高翻译效率和质量,编译器一般分为多个模块,每个模块负责完成一部分翻译工作,并生成中间结果。
这些中间结果可以是文本文件,也可以是二进制文件。
最后一个模块负责将所有中间结果合并成最终结果。
这些模块之间也有依赖关系,后面的模块需要使用前面模块生成的中间结果作为输入。
步骤c++编译可以分为四个阶段:预处理(preprocess),编译(compile),汇编(assemble)和链接(link)。
每个阶段都会生成对应的中间结果,并且有自己的工作内容和注意事项。
下面分别介绍每个阶段的具体内容。
预处理预处理是指对源代码进行一些文本替换和拷贝操作,以便于后续阶段进行语法分析和翻译。
预处理主要完成以下工作:-处理预处理指令(preprocessor directive),即以#开头的指令,比如#include, #define, #ifdef, #endif等。
c语⾔的预处理指令分3种 1宏定义 2条件编译 3⽂件包含宏简介1.C语⾔在对源程序进⾏编译之前,会先对⼀些特殊的预处理指令作解释(⽐如之前使⽤的#include⽂件包含指令),产⽣⼀个新的源程序(这个过程称为编译预处理),之后再进⾏通常的编译所有的预处理指令都是以#开头,并且结尾不⽤分号2.预处理指令分3种 1> 宏定义 2> 条件编译 3> ⽂件包含3.预处理指令在代码翻译成0和1之前执⾏4.预处理的位置是随便写的5.预处理指令的作⽤域:从编写指令的那⼀⾏开始,⼀直到⽂件结尾,可以⽤#undef取消宏定义的作⽤6.宏名⼀般⽤⼤写或者以k开头,变量名⼀般⽤⼩写 宏定义可以分为2种:不带参数的宏定义和带参数的宏定义。
⼀、不带参数的宏定义1.⼀般形式#define 宏名字符串⽐如#define ABC 10右边的字符串也可以省略,⽐如#define ABC2.作⽤它的作⽤是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常⽤来定义常量.3.使⽤习惯与注意1> 宏名⼀般⽤⼤写字母,以便与变量名区别开来,但⽤⼩写也没有语法错误2> 对程序中⽤双引号扩起来的字符串内的字符,不进⾏宏的替换操作。
3> 在编译预处理⽤字符串替换宏名时,不作语法检查,只是简单的字符串替换。
只有在编译的时候才对已经展开宏名的源程序进⾏语法检查4> 宏名的有效范围是从定义位置到⽂件结束。
如果需要终⽌宏定义的作⽤域,可以⽤#undef命令5> 定义⼀个宏时可以引⽤已经定义的宏名#define R 3.0#define PI 3.14#define L 2*PI*R#define S PI*R*R举例1 #include <stdio.h>2#define COUNT 434int main()5 {6char *name = "COUNT";78 printf("%s\n", name);910int ages[COUNT] = {1, 2, 67, 89};1112#define kCount 41314for ( int i = 0; i<COUNT; i++) {15 printf("%d\n", ages[i]);16 }1718// 从这⾏开始,COUNT这个宏就失效19#undef COUNT2021//int a = COUNT 写这个报错2223return0;24 }⼆、带参数的宏定义1.⼀般形式#define 宏名(参数列表) 字符串2.作⽤在编译预处理时,将源程序中所有宏名替换成字符串,并且将字符串中的参数⽤宏名右边参数列表中的参数替换3.使⽤注意1> 宏名和参数列表之间不能有空格,否则空格后⾯的所有字符串都作为替换的字符串2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进⾏任何计算操作。
预编译处理【学习目标】◇理解编译预处理的概念。
◇了解宏定义的概念,掌握简单宏定义和带参数的宏定义的格式和使用方法。
◇了解文件包含的概念,掌握文件包含的格式和使用方法。
能在程序中合理使用#include预处理指令◇了解条件编译的概念,掌握条件编译的三种格式及其使用方法。
能在程序中合理使用#define, #if, #ifndef, #else, #undef, #elif等指令。
【重点和难点】重点:编译预处理的概念,简单的宏定义与文件包含指令的用法。
难点:带参宏定义,条件编译指令,会用条件指令解决文件的重复包含问题。
【学习方法指导】本章的内容比较简单,严格说来,它也不算是C++语言的组成部分。
但是,一般说来,任何程序都离不开预编译指令。
特别是文件包含指令和条件编译指令,应把它们搞清楚。
虽然可以用宏定义的方法定义常数,但推荐使用const语句定义常量。
在编程中,如果我们能恰当地运用条件编译,就可以提高程序运行的效率。
【知识点】宏定义;宏替换;简单的宏定义;带参数的宏定义;文件包含;条件编译第一节宏定义我们用C++进行编程的时候,可以在源程序中包括一些编译命令,以告诉编译器对源程序如何进行编译。
这些命令包括:宏定义、文件包含和条件编译,由于这些命令是在程序编译的时候被执行的,也就是说,在源程序编译以前,先处理这些编译命令,所以,我们也把它们称之为编译预处理,本章将对这方面的内容加以介绍。
实际上,编译预处理命令不能算是C++语言的一部分,但它扩展了C++程序设计的能力,合理地使用编译预处理功能,可以使得编写的程序便于阅读、修改、移植和调试。
预处理命令共同的语法规则如下:◇所有的预处理命令在程序中都是以"#"来引导如"#include "stdio.h""。
◇每一条预处理命令必须单独占用一行,如"#include "stdio.h" #include <stdlib.h>" 是不允许的。
gcc编译过程的四个阶段1. 预处理(Preprocessing):预处理是编译过程的第一阶段。
预处理器负责对原始源文件进行处理,主要完成以下几个任务:-处理宏定义:预处理器会将源文件中的宏定义展开为相应的代码片段,并将其保存在一个临时文件中。
-处理条件编译指令:预处理器会根据条件编译指令的结果决定是否包含或排除一些代码片段。
- 处理#include指令:预处理器会将源文件中的#include指令所引用的其他文件插入到该指令所在的位置。
-移除注释:预处理器会删除源文件中的注释。
预处理后的文件成为扩展名为.i的中间文件,它包含了所有宏定义及展开后的代码。
编译是编译过程的第二阶段。
编译器将预处理生成的中间文件进行词法分析、语法分析和语义分析,生成相应的汇编代码。
主要过程如下:- 词法分析器将预处理生成的中间文件分解为一个个的词法单元(Token)。
- 语法分析器根据词法单元组织成的语法结构,生成抽象语法树(Abstract Syntax Tree,AST)。
-语义分析器对抽象语法树进行语义检查,包括类型检查和语义错误检查,确保程序的语义正确。
编译器将生成的汇编代码保存为扩展名为.s的汇编文件。
3. 汇编(Assembling):汇编是编译过程的第三阶段。
汇编器(Assembler)将编译器生成的汇编代码翻译成机器码,并生成目标文件。
具体过程如下:- 汇编器将汇编代码中的每一条汇编指令翻译成对应的机器码,同时为每个标号(Label)生成对应的地址。
-汇编器进行符号解析,将代码中引用的变量和函数与目标文件中的符号表进行匹配,生成正确的指令和地址。
汇编器将目标文件保存为扩展名为.o的目标文件。
4. 链接(Linking):链接是编译过程的最后阶段。
链接器(Linker)将目标文件与其他必要的库文件进行合并,生成最终的可执行文件或动态链接库。
主要过程如下:-链接器将目标文件中的函数和变量引用与其他目标文件中的定义进行匹配,解析外部引用,生成相应的引用表。
第九章编译预处理课题:第九章编译预处理教学目的:1、了解预处理的概念及特点2、掌握有参宏与无参宏的定义及使用,领会文件包含的使用及效果教学重点:教学难点:掌握宏的使用,文件包含有参宏与无参宏的使用步骤一复习引导ANSI C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。
这些预处理命令是由ANSI C统一规定的,但它不是C语言本身的组成部分,不能直接对它们进行编译。
必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行“预处理”,即根据预处理命令对程序作相应的处理。
经过预处理后程序不再包括预处理命令了,最后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。
步骤二讲授新课C语言与其他高级语言的一个重要区别是可以使用预处理命令和具有预处理的功能。
C 提供的预处理功能主要有以下三种:宏定义、文件包含、条件编译。
分别用宏定义命令、文件包含命令、条件编译命令来实现。
为了与一般C语句相区别,这些命令以符号“ #” 开头。
§9.1宏定义宏:代表一个字符串的标识符。
宏名:被定义为“宏”的标识符。
宏代换(展开):在编译预处理时,对程序中所有出现的“宏名”,用宏定义中的字符串去代换的过程。
一、不带参数的宏定义一般形式:#define 标识符字符串#define PI 3.1415926main(){ float l, s, r, v;printf( “input radius:” );scanf( “%f”, &r );l = 2.0*PI*r;s = PI*r*r;v = 3.0/4*PI*r*r*r;printf(“%10.4f,%10.4f,%10.4\n”, l, s, v);}例如:由键盘输入y值,求表达式:3(y2+3y)+ 4(y2+3y)+ y(y2+3y)#define M (y*y+3*y)main(){ int s, y;printf( “Input a number :”); scanf (“%d”,&y);s=3*M+4*M+y*M; p rintf(“s=%d\n”,s);}先宏展开:s=3*(y*y+3*y) +4*( y*y+3*y) + y*(y*y+3*y)再与源程序合并说明:⑴宏名一般用大写表示,以便与变量名区分。
编译预处理的名词解释编译预处理(Compiler preprocessor)是计算机科学中一个重要概念,它是编译器的前处理步骤,用于在源代码被编译前对其进行一系列的转换和操作。
编译预处理器是编译过程中的一个组件,它处理源代码中的预处理指令,对代码进行一些宏展开、条件编译等操作,然后再将处理后的代码提交给编译器进行编译。
一、编译预处理的定义和作用编译预处理是指在编译过程中对源代码进行处理的一系列操作。
预处理器会通过扫描源代码中的特殊指令,执行相应的操作,并将结果替换回源代码中。
预处理器可以实现代码的复用、条件编译、宏定义等功能,大大提高了代码的灵活性和可维护性。
编译预处理器最常用的功能之一是宏展开(Macro expansion)。
宏是一段预定义的代码片段,在代码中使用宏可以简化重复的代码,提高代码的可读性和维护性。
预处理器会将所有使用宏的地方替换为宏的定义内容,以此实现代码的复用。
二、条件编译条件编译(Conditional Compilation)是编译预处理中的一项重要功能。
通过条件编译,我们可以根据不同的条件选择性地编译源代码中的一部分。
这对于不同平台、不同版本的代码兼容性是非常有用的。
条件编译使用预处理指令#if、#ifdef、#ifndef、#elif、#else和#endif来实现。
我们可以根据条件表达式的结果来选择编译不同的代码块,从而实现特定条件下的代码执行。
三、头文件包含头文件包含(Header File Inclusion)是编译预处理中的另一个重要功能。
头文件包含用于将一个源文件中的代码引入到另一个源文件中。
这样,我们可以在不同的源文件中共享函数、常量、宏等定义,提高代码的复用性。
头文件被放置在使用它的源文件中,通常使用#include指令来进行包含。
头文件包含具有层次结构,可以通过嵌套的方式来引入多个头文件。
四、预定义宏预定义宏(Predefined Macros)是编译预处理器提供的一些内置宏,在编译过程中可供我们使用。
c语言的编译流程C语言是一种高级编程语言,被广泛用于系统软件、游戏开发、嵌入式系统等领域。
在使用C语言进行编程时,需要将代码转换为可执行文件,这个过程称为编译。
本文将介绍C语言的编译流程,以及编译过程的主要步骤。
1. 预处理(Preprocessing):编译过程的第一步是预处理,它由预处理器(Preprocessor)执行。
预处理器主要完成以下任务:- 处理以“#”开头的预处理指令,例如#include、#define、#ifdef 等。
- 将所有的#include指令替换为相应的头文件的内容。
-进行宏替换,将程序中的宏定义展开。
- 词法分析(Lexical Analysis):将代码分解为一个个的单词,称为记号(Token)。
- 语法分析(Syntax Analysis):根据语法规则组织单词,并创建语法树(Syntax Tree)。
- 语义分析(Semantic Analysis):对语法树进行分析,检查语义错误,并生成中间代码。
3. 汇编(Assembly):编译器生成的中间代码是与特定平台无关的,需要通过汇编器(Assembler)将其转换为可执行文件。
汇编器主要完成以下任务:-将汇编代码转换为机器码指令。
-将符号名称解析为地址,生成可重定位代码。
4. 链接(Linking):在C语言编程中,通常会使用多个源文件,这些文件中的函数和变量可能相互引用。
链接器(Linker)的作用是将这些文件中的符号引用和定义进行匹配,生成最终的可执行文件。
链接器主要完成以下任务:- 符号解析(Symbol Resolution):将符号引用与符号定义进行匹配。
- 地址重定位(Address Relocation):将代码中的相对地址转换为绝对地址。
- 符号合并(Symbol Merging):将多个源文件中同名的符号进行合并,以解决重复定义的问题。
-生成可执行文件,包括代码段、数据段等。
5. 加载(Loading):加载器(Loader)是操作系统提供的一部分,它将可执行文件加载到内存中,并执行程序。
C语⾔对源程序处理的四个步骤:预处理、编译、汇编、链接——预处理篇预处理1)预处理的基本概念C语⾔对源程序处理的四个步骤:预处理、编译、汇编、链接。
预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进⾏的处理。
这个过程并不对程序的源代码语法进⾏解析,但它会把源代码分割或处理成为特定的符号为下⼀步的编译做准备⼯作。
2)预编译命令C编译器提供的预处理功能主要有以下四种:1)⽂件包含 #include2)宏定义 #define3)条件编译 #if #endif ..4)⼀些特殊作⽤的预定义宏a、⽂件包含处理1)⽂件包含处理⽂件包含处理”是指⼀个源⽂件可以将另外⼀个⽂件的全部内容包含进来。
C语⾔提供了#include命令⽤来实现“⽂件包含”的操作。
2)#include< > 与 #include ""的区别" "表⽰系统先在file1.c所在的当前⽬录找file1.h,如果找不到,再按系统指定的⽬录检索。
< >表⽰系统直接按系统指定的⽬录检索。
注意:1. #include <>常⽤于包含库函数的头⽂件2. #include " "常⽤于包含⾃定义的头⽂件 (⾃定义的头⽂件常⽤“ ”,因为使⽤< >时需要在系统⽬录检索中加⼊⾃定义头⽂件的绝对地址/相对地址否则⽆法检索到该⾃定义的头⽂件,编译时会报错)3. 理论上#include可以包含任意格式的⽂件(.c .h等) ,但我们⼀般⽤于头⽂件的包含。
b、宏定义1)基本概念在源程序中,允许⼀个标识符(宏名)来表⽰⼀个语⾔符号字符串⽤指定的符号代替指定的信息。
在C语⾔中,“宏”分为:⽆参数的宏和有参数的宏。
2)⽆参数的宏定义#define 宏名 字符串例: #define PI 3.141926在编译预处理时,将程序中在该语句以后出现的所有的PI都⽤3.1415926代替。
C/C++编译过程C/C++编译过程主要分为4个过程1) 编译预处理2) 编译、优化阶段3) 汇编过程4) 链接程序一、编译预处理(1)宏定义指令,如#define Name TokenString,#undef等。
对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的Name则不被替换。
对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。
预编译程序将根据有关的文件,将那些不必要的代码过滤掉(3)头文件包含指令,如#include "FileName"或者#include <FileName>等。
在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。
包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。
在程序中#include它们要使用尖括号(< >)。
另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。
(4)特殊符号,预编译程序可以识别一些特殊的符号。
例如在源程序中出现的#line标识将被解释为当前行号(十进制数),上面程序实现了对宏line的运用(5)预处理模块预处理工作由#pragma命令完成,#Pragma命令将设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
c编译过程的五个阶段C语言是一种高级编程语言,但是计算机并不能直接识别高级语言,必须经过编译器的编译过程将高级语言转换为计算机能够识别的低级机器语言,才能够在计算机上运行。
C语言的编译过程可以分为五个阶段,分别是预处理、编译、汇编、链接和装载。
第一阶段:预处理预处理器是编译器的一个组成部分,它的主要作用是对源代码进行扫描并根据其中包含的预处理指令进行处理,生成一个新的预处理后文件。
预处理器的预处理指令包括宏定义、条件编译、包含文件和其他一些预处理指令。
预处理后文件包括宏定义的内容和用#define定义的宏以及其他预处理指令处理后的结果,该操作相当于在程序代码前加上一些特定操作。
第二阶段:编译编译阶段的主要工作是将预处理过的代码转换为汇编语言,也就是将C语言源代码翻译成汇编语言,生成一个汇编语言文件。
在这个阶段,编译器会对代码进行词法分析、语法分析、语义检查等处理,将源代码转换为计算机能够理解和执行的低级指令。
第三阶段:汇编汇编阶段是将汇编语言文件转换成机器语言文件的过程。
在这个阶段中,汇编器将汇编语言代码转换为计算机实际可以执行的二进制代码(即机器代码),生成一个目标文件。
目标文件是由一系列二进制代码组成的文件,其中包括程序代码和数据。
第四阶段:链接链接器将被编译的源文件和其他库文件链接在一起形成一个可执行的程序。
在这个阶段,链接器将目标文件中的符号表和地址关联起来,组成最终可执行程序。
链接的目标文件可以是静态库文件(.a)、动态库文件(.so)或者是其他可执行文件。
第五阶段:装载装载是将可执行程序加载到内存中并运行的过程。
在这个阶段中,操作系统将可执行程序的代码和数据加载到指定的内存区域,把程序从磁盘中加载到内存中,然后操作系统将控制权交给这个程序,程序开始执行。
总体来说,C语言编译过程是将高级语言转换成计算机可以理解的低级机器语言的过程,主要包括预处理、编译、汇编、链接和装载五个阶段。
在这个过程中,逐步掌握和理解每个阶段的工作和作用,能够更好地理解程序的编译、调试和性能优化等方面。
程序编译的四个步骤程序的编译过程通常分为四个步骤:预处理、编译、汇编和链接。
第一步:预处理(Preprocessing)预处理是编译过程的第一个步骤。
在这一步骤中,预处理器将对源代码进行处理,以便于后续的编译。
预处理器通常会执行以下任务:1.去除注释:将源代码中的注释(单行、多行注释)删除,以便于后续的处理。
2.展开宏定义:替换源代码中的宏定义,在源代码中使用宏定义的地方,将其替换为宏定义的内容。
3.处理条件编译指令:根据条件编译指令的条件,决定哪些代码需要编译,哪些代码需要忽略。
4.处理头文件包含指令:将头文件包含指令替换为头文件的内容,以确保源代码中可以使用头文件中定义的函数、变量等。
编译是预处理之后的一步,编译器将对预处理后的文件进行处理。
编译器通常会执行以下任务:1. 词法分析(Lexical Analysis):将源代码分解成一个个的词素,如关键字、标识符、运算符等,并生成相应的记号。
2. 语法分析(Syntax Analysis):根据词法分析生成的记号,将其按照一定的文法规则进行组织,构建抽象语法树。
3. 语义分析(Semantic Analysis):对抽象语法树进行分析,检查程序是否存在语义错误,如类型不匹配、未定义的变量等。
4. 代码生成(Code Generation):根据语义分析的结果,将抽象语法树转化为目标机器的汇编代码。
第三步:汇编(Assembly)汇编是编译过程的第三步,将编译器生成的汇编代码转化为机器码。
汇编器(Assembler)会执行以下任务:1.识别指令和操作数:根据汇编代码的语法规则,识别出每个指令以及对应的操作数。
2.生成机器码:将汇编指令和操作数翻译成机器码表示形式。
3.符号解析:解析并处理所有的符号引用,如函数、变量等的引用。
第四步:链接(Linking)链接是编译过程的最后一步,将编译器生成的目标代码和其他库文件进行合并。
1.解析外部符号引用:将目标代码中引用的外部符号(函数、变量等)与其他目标代码或库文件中的定义进行匹配。
C语言程序的编译流程C语言是一种高级程序设计语言,常用于开发各种应用程序和系统软件。
在将C语言程序转化为可执行的计算机程序之前,需要经过编译的流程。
本文将详细介绍C语言程序的编译流程,包括预处理、编译、汇编和链接等步骤。
1. 预处理(Preprocessing)在编译过程中的第一步是预处理。
预处理器会对源代码进行处理,去除注释、替换宏定义、展开头文件等。
预处理的输出是一个经过修改的源文件,通常以.i作为文件扩展名。
预处理器还可以通过条件编译来控制程序中特定代码块的编译。
这对于根据不同平台或配置条件选择不同代码实现非常有用。
2. 编译(Compiling)预处理之后,进入编译阶段。
编译器会将预处理生成的.i文件翻译成汇编语言。
汇编语言是一种简单的低级语言,使用助记符来表示计算机指令。
编译的输出通常以.s作为文件扩展名。
编译器会对源代码进行语法分析和语义分析,并将其转化为中间表示。
中间表示是一种介于源代码和汇编语言之间的抽象语言形式,使得优化和目标代码生成更容易。
3. 汇编(Assembling)在汇编阶段,汇编器将汇编语言翻译成机器语言。
机器语言是计算机可以直接执行的二进制指令。
汇编的输出通常以.obj或.o作为文件扩展名。
汇编器会将汇编代码转化为可重定位目标代码(relocatable object code)。
可重定位目标代码包含机器指令、符号表和重定位信息等。
4. 链接(Linking)最后一步是链接阶段。
链接器将一个或多个目标文件链接在一起,形成最终的可执行文件。
链接的输出可以是可执行文件、静态库或动态库。
链接器会解析目标代码中的符号引用,并将其与其他目标文件中的符号定义进行关联。
同时,链接器还会执行地址重定位,将目标文件中的相对地址转化为绝对地址,以便正确地执行程序。
链接可以分为静态链接和动态链接。
静态链接将编译后的目标代码和库代码合并在一起,生成独立的可执行文件。
动态链接则在程序运行时才将所需的库代码加载到内存中。
1、预处理1、预处理命令的定义 使⽤库函数之前,应该⽤#include引⼊对应的头⽂件。
这种以#号开头的命令称为预处理命令。
所谓预处理是指在进⾏编译时的第⼀遍扫描(词法扫描和语法分析)之前所做的⼯作。
预处理是C语⾔的⼀个重要功能,它由于处理程序负责完成。
当编译⼀个程序时,系统将⾃动调⽤预处理程序对程序中“#”开头的预处理部分进⾏处理,处理完毕之后可以进⼊源程序的编译阶段。
C语⾔源⽂件要经过编译、链接才能⽣成可执⾏程序: (1)编译(Compile)会将源⽂件(.c⽂件)转换为⽬标⽂件。
对于 VC/VS,⽬标⽂件后缀为.obj;对于GCC,⽬标⽂件后缀为.o。
编译是针对单个源⽂件的,⼀次编译操作只能编译⼀个源⽂件,如果程序中有多个源⽂件,就需要多次编译操作。
(2)链接(Link)是针对多个⽂件的,它会将编译⽣成的多个⽬标⽂件以及系统中的库、组件等合并成⼀个可执⾏程序。
在实际开发中,有时候在编译之前还需要对源⽂件进⾏简单的处理。
例如,我们希望⾃⼰的程序在 Windows 和 Linux 下都能够运⾏,那么就要在 Windows 下使⽤ VS 编译⼀遍,然后在 Linux 下使⽤ GCC 编译⼀遍。
但是现在有个问题,程序中要实现的某个功能在 VS 和GCC 下使⽤的函数不同(假设 VS 下使⽤ a(),GCC 下使⽤ b()),VS 下的函数在 GCC 下不能编译通过,GCC 下的函数在 VS 下也不能编译通过,怎么办呢? 这就需要在编译之前先对源⽂件进⾏处理:如果检测到是 VS,就保留 a() 删除 b();如果检测到是 GCC,就保留 b() 删除 a()。
这些在编译之前对源⽂件进⾏简单加⼯的过程,就称为预处理(即预先处理、提前处理)。
预处理主要是处理以#开头的命令,例如#include <stdio.h>等。
预处理命令要放在所有函数之外,⽽且⼀般都放在源⽂件的前⾯。
预处理是C语⾔的⼀个重要功能,由预处理程序完成。
C语言编译执行的全过程1.预处理预处理是编译过程的第一步,主要作用是对源代码进行一些处理,生成预处理后的文件。
预处理主要包括以下几个操作:-删除注释:删除源代码中的注释。
注释对于程序的执行没有影响,但会增加源代码长度,降低可读性。
- 处理预处理指令:处理以"#"开头的预处理指令,如#include、#define等。
-展开宏定义:将源代码中的宏定义展开为对应的代码。
-处理条件编译指令:根据条件编译指令的条件判断结果,选择性地编译部分代码。
2.编译编译是将预处理后的文件转换为汇编代码的过程。
编译主要包括以下几个步骤:-词法分析:将源代码分割为一个个的词法单元,如关键字、标识符、常量、操作符等。
-语法分析:根据词法单元组成规则进行语法分析,生成抽象语法树。
-语义分析:对抽象语法树进行语义检查,如类型检查、函数调用检查等。
-生成中间代码:根据语法分析和语义分析的结果,生成中间代码。
3.汇编汇编是将编译后的中间代码转换成机器码的过程。
中间代码并不是直接可执行的,在汇编过程中,会将中间代码转换为与目标硬件平台相对应的机器指令。
汇编主要包括以下几个步骤:-词法分析:将中间代码分割为一个个的词法单元。
-语法分析:根据词法单元组成规则进行语法分析,生成抽象语法树。
-生成目标代码:根据抽象语法树生成目标代码。
4.链接链接是将编译后的目标代码与库函数进行合并,生成可执行文件的过程。
链接主要包括以下几个步骤:-符号解析:解析目标代码中的符号引用,确定其所对应的符号定义。
-重定位:根据符号解析的结果,将目标代码中的符号引用跳转至对应的符号定义。
-地址和空间分配:为所有的可执行代码和数据分配内存空间。
5.执行执行是将可执行文件加载到计算机内存中,并按照指令序列依次执行。
执行主要包括以下几个步骤:-内存加载:将可执行文件加载到内存中。
-程序入口:开始执行程序的入口点。
-按顺序执行指令:根据程序计数器(PC)指向的地址,按顺序执行一条条的机器指令。
一、选择题1、函数调用语句int fun( ) { return 50,60; },则函数调用后返回值为()。
A、50B、60C、50,60D、编译错2、设有函数定义调用语句“f((e1,e2),(e3,e4,e5));”,则实参个数是()。
A、2B、3C、4D、53、若用下列程序f(char a){ float b=5;b+=a/b;return b;}则函数返回值的类型是()。
A、intB、charC、voidD、float4、若定义函数int f(int x) { x++; return x; }执行以下语句:int a=5; f(a)+f(a);则a的值是()。
A、5B、6C、7D、85、下列程序的运行结果是()。
fun1(int a, int b){ return fun2(a++, --b); }fun2(int a, int b){ return a/b; }void main( ){ int x=5, y=6;cout<<fun1(x,y);}A、1B、1.6C、2D、语法错6、以下程序执行后输出结果是()。
int f(int x,int y){ return (y-x)*x; }void main( ){ int a=3, b=4, c=5, d;d=f(f(a,b),f(a,c));cout<<d;}A、3B、8C、9D、67、设有宏定义和语句#define P(x, y) x/y#define PP(a,b) a*bint c=P(2+3, 2+3)+PP(2+3, 2+3);则变量C的值是()。
A、26B、17C、17.5D、318、若有定义int k=3,以k+1作为参数,对下列宏定义进行宏展开,则最终结果不为7的是()。
A、#define s(x) x*xB、#define s1(x) (x)*(x)C、#define s2(x) (x*x)D、#define s4(x) (x*(x))9、下列编译预处理指令没有语法错误的是()。
A、#define N 3=B、#inc lude “iostream.h”;C、#define PI=3.14159D、include”iostream.h”10、在下面的函数声明中,存在着语法错误的是()。
A、void A(int a, int)B、void B(int, int)C、void C(int, int=5)D、int D(int x; int y)11、在程序中,函数声明语句正确位置是()。
A、随便任何位置B、不包含在另一函数中的任何位置C、该函数使用前的任何位置D、该函数使用前的任何位置,但包含在另一函数中12、下面保留字中不能作为函数的返回类型的是()。
A、voidB、intC、newD、long13、设有函数定义F(int &i),变量定义int n=10,则下面调用正确的是()。
A、F(20)B、F(10+n)C、F(n)D、F(&n)14、在一个函数中定义的静态变量的作用域为()。
A、本程序的全部范围B、本函数的全部范围C、从定义该变量的位置开始到本文件结束D、以上说法都不正确15、对于下面几个函数函数:void f(int x) {…} //1int f(int y) {…} //2int f(int i, int j) {…} //3float k(int x) {…} //4()是重载函数。
A、4个全部B、1和4C、2和3D、3和416、以下描述正确的是()。
A、函数定义可以嵌套,函数调用也可以嵌套B、函数定义不可以嵌套,函数调用可以嵌套C、函数定义不可以嵌套,函数调用也不可以嵌套D、函数定义可以嵌套,函数调用不可以嵌套17、以下描述正确的是()。
A、调用函数时,只能把实参的值传递给形参,形参的值不能传递给实参B、函数既可以嵌套定义,又可以递归调用C、函数必须有返回值,否则不能被调用D、函数只能调用同一个源程序文件中定义的其他函数18、以下描述正确的是()。
A、函数中,return后面一定要有表达式B、函数中,不可以有多条return语句C、函数返回值一定要通过return语句返回D、return语句是函数中不可缺少的语句19、在C++语言程序中,当调用函数时,()。
A、实参和形参各占一个独立的存储单元B、实参和形参可以共用存储单元C、可以由用户指定是否共用存储单元D、计算机系统自动确定是否共用存储单元20、有函数定义如下f(int a) { return a++; }并有定义float f=5.88; char c=”d”;则以下不合法的函数调用语句是()。
A、f(2,3);B、f(f);C、f((2,3));D、f( c);21、有函数定义f(int a, int b) { return a++;}则以下对函数f的原型说明不正确的是()。
A、f(int a, int b)B、f(int, int);C、f(int s, int y);D、f(int s, int);22、若有函数调用语句f(g(x,y),z=x+y,(x+y))中,实参的个数是()。
A、3B、4C、5D、623、关于下列叙述正确的是()。
void f(int a) {…} //1int f(int a,int b) {…} //2int f(int b) {…} //3A、1和2是重载函数B、1和3是重载函数C、都是重载函数D、都不是重载函数24、下列叙述正确的是()。
A、一个include可以用于包含一个或多个文件B、编译预处理命令必须以#开始C、使用include包含的文件一定要以.h为后缀D、程序执行时,宏展开只作替换,而不含计算过程25、下列编译预处理命令正确的是()。
A、#define MUL(int a, int b) a*bB、#include ”iostream.h”C、#define MUL(int a) a*bD、#include “iostream.h”, ”math.h”26、以下程序的输出结果是()。
#include<iostream.h>#define T(x,y) (x)<(y)?(x): (y)void main( ){ int i,j,k;i=10; j<15; k=10*T(I,j);cout<<k<<endl;}A、15B、100C、10D、15027、以下程序的运行结果是()。
#include<iostream.h>int func(int a, int b){ static int m, i=2;i+=m+1;m=i+a+b;return m;}void main( ){ int k=4, m=1, p;p=func(k,m);cout<<p<<’,’;p=func(k,m);cout<<p<<endl;}A、8,17B、8,16C、8,20D、8,8二、填空题1、若自定义函数要求返回一个值,则应在该函数体中有一条()语句;若自定义函数要求不返回值,则应在该函数定义时加一个类型符()。
2、静态整型变量的缺省初值为()。
3、函数的调用方式分为()、()、()。
4、在一个函数的定义或者声明前加上关键字()时,该函数就声明为内联函数。
5、程序第一行的结果是(),第二行的结果是()。
void fun(int x, int y){ int t;t=x; x=y; y=t;cout<<”x=”<<x<<’\t’<<”y=”<<y<<’\n’;}void main( ){ int a=4, b=5;fun(a,b);cout<<”a=”<<a<<’\t’<<”b=”<<b<<’\n’;}6、以下程序输出的第一行是(),第二行的结果是()。
#include<iostream.h>void s(int a,int &b){ int t=a; a=b; b=t; }void main( ){ int x=500, y=1000;cout<<x<<’\t’<<y<<’\n’;s(x,y);cout<<x<<’\t’<<y<<’\n’;}7、程序的输出的结果是()。
void fun( ){ static int a=0;a+=2;cout<<a<<’\n’;}void main( ){ int c;for(c=1; c<3; c++)fun( );}8、以下程序的输出的第一行是(),第三行的结果是()。
#include<iostream.h>void fn(int &x){ static int y=10;x+=y; y+=x;cout<<x<<”,”<<y<<endl;}void main( ){ int y=1;fn(y); fn(y); fn(y);}9、程序运行的结果是()。
int x=100;void main( ){ int x=200;x+=::x;{ int x=500;::x+=x;}cout<<x<<’\t’<<::x;}10、以下程序的运行结果()。
#include<iostream.h>void f1(int n){ cout<<n%10;if(n/10) f1(n/10);}void f2(int n){ int j=n%10;if(n/10) f2(n/10);cout<<j;}void main( ){ f1(1234);cout<<’\n’;f2(1234);cout<<’\n’;}11、程序运行结果是()。
int m(int a, int b);int m(int a, int b, int c);void main( ){ cout<<m(15,85,42); }int m(int a, int b){ return a; }int m(int a, int b, int c){ int t=m(a,b);return t;}12、下列程序第一行的结果是(),第二行的结果是()。
#include<iostream.h>int f(int a){ static float b=2;return b+=a/b;}void main( ){ for(int i=3; i<5; i++) cout<<f(i)<<’\n’; }13、下列程序运行后第一行至第三行分别是()、()、()。