|
|
51CTO旗下网站
|
|
移动端

1.15 编译原理(2)

《程序员面试笔试真题与解析》本书针对当前各大 IT企业面试笔试中特性与侧重点,精心挑选了 3年以来近百家典型 IT企业的面试笔试真题,这些企业涉及业务包括系统软件、搜索引擎、电子商务、手机 APP、安全关键软件等,面试笔试真题非常具有代表性与参考性。本节为大家介绍编译原理。

作者:猿媛之家来源:机械工业出版社|2017-12-06 18:31

1.15 编译原理(2)

从上表的分析可知,下推自动机属于 2型语言。所以,选项 C正确。

【真题 221】现代语言(例如 Java语言)的编译器的词法分析主要依靠(A.有限状态自动机 B.确定下推自动机 C.非确定下推自动机 答案:A。 )。 D.图灵机

有限状态自动机( Finite State Automaton,FSA)是为研究有限内存的计算过程和某些语言类而抽象出的一种计算模型。有限状态自动机拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。有限状态自动机可以表示为一个有向图。有限状态自动机是自动机理论的研究对象。所以,选项 A正确。

下推自动机﹙ Push Down Automaton,PDA﹚是自动机理论中定义的一种抽象的计算模型。下推自动机比有限状态自动机复杂:除了有限状态组成部分外,还包括一个长度不受限制的栈;下推自动机的状态迁移不但要参考有限状态部分,也要参照栈当前的状态;状态迁移不但包括有限状态的变迁,还包括一个栈的出栈或入栈过程。术语“下推”来自原型机械自动机物理上接触穿孔卡片来阅读其内容的下推动作。术语“确定下推自动机”( Deterministic Push Down Automaton,DPDA)指的是识别确定上下文无关语言的抽象计算设备。

图灵机,又称图灵计算、图灵计算机,是由数学家阿兰 ·麦席森·图灵( 1912~1954年)提出的一种抽象计算模型,它有一条无限长的纸带,纸带分成了一个一个的小方格,每个方格有不同的颜色。有一个机器头在纸带上移来移去,机器头有一组内部状态,还有一些固定的程序。在每个时刻,机器头都要从当前纸带上读入一个方格信息,然后结合自己的内部状态查找程序表,根据程序输出信息到纸带方格上,并转换自己的内部状态,然后进行移动。

词法分析( Lexical Analysis)是计算机科学中将字符序列转换为单词( Token)序列的过程,是编译过程的第一个阶段。完成词法分析任务的程序称为词法分析程序(也叫词法分析器或扫描器)。从左至右地对源程序进行扫描,按照语言的词法规则识别各类单词,并产生相应单词的属性字。词法分析器一般以函数的形式存在,供语法分析器调用。

通过上述分析可知,词法分析主要依靠有限状态自动机进行。所以,选项 A正确。

【真题 222】程序的完整编译过程分为预处理、编译和汇编等几个过程,以下关于编译阶段的编译优化的描述中,不正确的是()。

A.死代码删除指的是编译过程直接抛弃掉被注释的代码

B.函数内联可以避免函数调用中压栈和退栈的开销

C.for循环的循环控制变量通常很适合调度到寄存器访问

D.强度削弱是指执行时间较短的指令等价地替代执行时间较长的指令答案:A。程序的一个完整编译过程通常包括几个步骤:预处理(例如 .c文件)、编译、优化( .s、.asm文件)、

汇编( .obj、.o、.a、.ko)和链接( .exe、.elf、.axf)等。其中,预处理阶段的主要任务是读取源程序,对其中的伪指令(以 #开头的指令)和特殊符号进行处理。编译阶段的主要任务是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码或汇编代码,而优化涉及的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系,优化一部分是对中间代码的优化,这种优化不依赖于具体的计算机设备,另一部分则主要针对目标代码的生成而进行。汇编阶段的主要任务是把汇编语言代码翻译成目标机器指令。链接程序的主要任务是将有关的目标文件彼此相连接,即把在一个文件中引用的符号同该符号在另外一个文件中的定义链接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

本题中,对于选项 A,如果一个变量的值以后还要被引用,那么称这个变量在程序的该点是活跃的,否则,称它在该点是死亡的,而所谓死代码指的是其计算结果永远不会被使用的语句,例如: while(false){}、 if(0){…},由于其执行条件永远不成立,所以,大括号里的代码就是死代码,需要注意的是,死代码不是直接抛弃被注释的代码。所以,选项 A错误。

对于选项 B,考察的是对内联函数的理解。内联函数通常由关键字 inline修饰,它是真正的函数,是通过编译器控制来实现的。只是在需要用到的时候,它会像宏一样地展开,所以,取消了函数的参数压栈过程,减少了调用的开销。所以,选项 B正确。

对于选项 C,在大多数的机器上,函数的调用都是一个复杂的过程:调用前保存寄存器,并在返回时恢复;复制实参;程序转向一个新位置执行。而 CPU在内存中取循环控制遍历需要一定的时间,如果该变量的值存放在寄存器中,那么效率会更高。而且,当前很多编译器默认做了此类优化,所以,下面的代码在实际开发中并不常见。

  1. #include<iostream> 
  2. using namespace std;  
  3. int main()  
  4. {  
  5. register int i = 0;  
  6. for (i = 0; i < 100; i++)  
  7. {  
  8. cout << i << endl;  
  9. }  
  10. return 0;  

所以,选项 C正确。

对于选项 D。所谓强度削弱,指的是用一种(或一串)执行时间较短的操作去等价地代替一个操作。简单说,就是不让强度太大或用执行时间较短的操作(指令)去代替一个耗时操作。例如,乘以 2的 n次方运算可以通过将该数左移 n位来实现,毕竟在绝大多数机器上,移位运算的速度比乘法运算的速度快。所以,选项 D正确。

所以,本题的答案为 A。

【真题 223】以下关于编译链接的描述中,错误的是()。

A.编译优化会使得编译速度变慢 B.预编译头文件可以优化程序的性能

C.静态链接会使得可执行文件偏大 D.动态链接库会使进程启动速度偏慢答案:B。编译器对源代码进行编译,是将以文本形式存在的源代码翻译为机器语言形式的目标文件的过程。

链接是指在程序的多个模块之间传递参数和控制命令,把它们整合成一个可执行的整体程序。本题中,对于选项 A,影响编译速度的因素比较多,主要有以下几点内容:

①文件的大小,文件大小指的是全部 include(包含)展开后的大小,会影响编译速度。

②文件数量,编译是一个一个文件进行的,所以,工程的文件数量也会影响编译速度。

③声明的复杂程度,复杂声明需要额外地计算,会影响编译速度。

④ C++模板在编译的时候要进行推导,得到相应的结果,这个过程非常费时。如果模板里还嵌套了模板,速度就更慢了。

⑤链接库的数量会影响编译速度,链接库越多,编译速度越慢。

⑥ inline函数展开,会使得代码膨胀,影响编译速度。

⑦ debug(调试)模式下编译要留符号表做调试,会影响编译速度。

⑧ release(发布)模式如果使用了优化,编译优化会改变代码的某些结构,会使得编译速度减慢。其实,除了以上代码级的优化以外,还有通过外在的方法提高编译速度的方法,具体如下:

①更好的磁盘,编译的时候往往需要对磁盘进行操作,所以,加快磁盘的处理速度往往也可以提高编译速度,例如 SSD(Solid State Drives,固态硬盘)或者 RAID0(又称为 Stripe或 Striping,它代表了所有 RAID级别中昀高的存储性能)磁盘。

②分布式编译,其原理就是将编译的整个过程通过分布计算的方法分配到多个计算机上执行,以获得极大地效率提升。

③并行,假设有模块 A和模块 B,B依赖于 A,所以,必须在 A之后编译 B。其中 A、B编译各需要 1个小时,那么总共要 2个小时,可是 B一定要在 A之后 build(构建)吗?答案是否定的,完全可以同时编译 A和 B,如果 A编译成功,而 B编译失败了,但都只是失败在昀后的链接上,重新链接 B即可,并行编译通常采用多核的方式,例如 4核、8核甚至更多核。

通过以上分析可知,选项 A正确。

对于选项 B,预编译又称为预处理,在此期间,主要进行代码文本的替换,是整个编译过程中昀先做的工作,它不涉及代码本身的优化级别,更不会修改代码,所以,同样的内容不可能产生程序性能的优化。所以,选项 B错误。

对于选项 C,静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。静态链接的昀大缺点是生成的可执行文件太大,需要更多的系统资源,在装入内存时也会消耗更多的时间。所以,选项 C正确。

对于选项 D,动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 文件中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。操作系统的加载程序会执行下面的步骤:加载程序先为新的进程创建一个虚拟地址空间,并将可执行模块映射到新进程的地址空间中。加载程序接着解析可执行模块的导入段。对导入段中列出的每个 DLL,加载程序会在用户的系统中对该 DLL模块进行定位,并将该 DLL映射到进程的地址空间中。注意,由于 DLL模块可以从其他 DLL模块中导入函数和变量,因此, DLL模块可能有自己的导入段并需要把 DLL模块映射到进程的地址空间中。可以看到,初始化一个进程可能会耗费很长的时间。因此,选项 D正确。

所以,本题的答案为 B。

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

ASP.NET 2.0数据库开发实例精粹

本书分为8章,首先介绍ASP.NET的开发技巧和重点技术,尤其针对初学者如何快速入门并掌握ASP.NET编程做了深入浅出的介绍;然后重点介绍ASP.N...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊