嵌入式-C语言(二)

1.宏定义是在编译的哪个阶段被处理的?

  宏定义是在编译预处理阶段被处理的。
解读:编译预处理:头文件包含、宏替换、条件编译、去除注释、添加行号。
(1)预处理:引入头文件、进行宏替换、处理条件编译指令、去除注释、添加行号。
(2)编译:进行语法分析、词法分析、语义分析符号汇总等,并生成汇编代码.s。
(3)汇编:将汇编代码转成二进制代码,二进制文件就可以让机器来读,每一句汇编代码都会产生一句机器语言。最终生成重定位目标文件.o文件(目标文件)。
(4)链接:将有关的目标文件彼此连接为可执行代码。分为静态链接(将库文件代码搬迁到可执行文件中,后缀是.a)和动态链接(在执行的时候转到库文件代码执行,后缀是.so)。

2.什么是预编译,何时需要预编译

  预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。C提供的预处理功能主要有以下三种:

  • 1)宏定义
  • 2)文件包含
  • 3)条件编译

3.预处理部分命令

#define            //定义一个预处理宏
#undef             //取消宏的定义
#if                //编译预处理中的条件命令,相当于C语法中的if语句
#ifdef             //判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef            //与#ifdef相反,判断某个宏是否未被定义
#elif              //若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if(扩展条件)
#else              //与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else(扩展条件)
#endif             //#if, #ifdef, #ifndef这些条件命令的结束标志.
#defined          //与#if, #elif配合使用,判断某个宏是否被定义

4.静态链接于动态连接的优缺点

  • 静态的链接产生的可执行文件体积比较大,而动态连接的可执行文件体积较小。
  • 动态的链接编译效率比较高
  • 静态链接的可执行文件的执行效率比较高
  • 静态链接的可执行的文件的“布局”比较好一点

5.静态链接和动态连接有什么区别

  静态链接将库文件代码搬迁到可执行文件中,成为可执行文件的一部分,即该文件包含了运行时的全部代码。其优点是:在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行。缺点是:当多个程序调用同一个函数时,内存中就会存在这个函数的多个复制,浪费了内存资源。
  动态连接调用的的函数代码并没有复制到内存中,仅仅在其中加入了所调用函数的描述信息,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。其优点是: 多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝。缺点是:由于是运行时加载,可能会影响程序的前期执行性能。

6.静态链接库和动态连接库有什么区别

  • 由于静态库是在编译期间直接将代码合到可执行程序中,而动态库是在执行期时调用DLL中的函数体,所以执行速度比动态库要快一点;
  • 静态库链接生成的可执行文件体积较大,且包含相同的公共代码,造成内存浪费;
  • 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;
  • DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性,适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。

7.静态链接库和动态连接库有什么区别

  • 带参宏只是在编译预处理阶段进行简单的字符替换;而函数则是在运行时进行调用和返回。
  • 宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
  • 带参宏在处理时不分配内存;而函数调用会分配临时内存。
  • 宏不存在类型问题,宏名无类型,它的参数也是无类型的;而函数中的实参和形参都要定义类型,二者的类型要求一致。
  • 而使用宏定义次数多时,宏替换后源程序会变长;而函数调用不使源程序变长。

8.const与#define的异同?

  • 异:const有数据类型,编译器可以做静态类型检查;而宏定义没有类型,可能会导致类型出错。
  • 同:两者都可用来定义常数。

9.const与#define 相比,有何优点?

  • Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
  • const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
  • 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试

10.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。

#define  MIN(A, B)  ((A) <= (B)? (A) : (B))

11.已知数组table,用宏求数组元素个数。

#define  COUNT(table)  (sizeof(table) / sizeof(table[0])) 

12.下面代码能不能编译通过?

#define c 3  
c++; 

不能。因为自增运算符++用于变量,3是常量。

13.预处理器标识#error的作用是什么?

编译程序时,只要遇到 #error 就会跳出一个编译错误。
当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,可写如下预处理代码:

#ifdef XXX  
#error "XXX has been defined"  
#else  
	…  
#endif  

如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了

14.用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define  SECONDS_PER_YEAR  (60 * 60 * 24 * 365)UL 
  • 注意预处理器将为你计算常数表达式的值,并且整个宏体要用括号括起来。
  • 注意这个表达式将使一个16位机的整型数溢出,因此要用到无符号长整型符号UL,告诉编译器这个常数是的无符号长整型数。

15.typedef和define

typedef和define都是替一个对象取一个别名,来增强程序的可读性,但他们也存在以下4个不同:

原理不同

  • define是C语言规定的语法,他是预处理命令,在预处理阶段进行简单而又机械的字符串替换,不做正确性检查;只有在编译阶段才会发现可能的错误并报错。
  • typedef是关键字,在编译时处理,所以具有类型检查的功能,它在自己的作用域内对已存在的类型一个别名,但切记不能在一个函数定义里使用标识符typedef。

功能不同

  • typedef用来定义类型的别名,这些类型不仅包括内部类型(int、char等),还包括自定义类型(如struct),使得类型更加容易记忆。此外,还有一个重要的用途,就是定义机器无关的类型。
  • define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。

作用域不同

define没有作用域的限制,只要是预定义过的宏,在以后的程序中都可以使用。而typedef有自己的作用域.

16. NUL与NULL

牢记下面的话,它有助于回忆指针和ASCII码零的正确术语:
一个‘L’的NUL用于结束一个ASCII字符串
两个‘L’的NULL用于表示什么也不指向(空指针)
ASCII字符中零的位模式被称为‘NUL’。表示哪里也不指向的特殊的指针则是‘NULL’,这两个术语不可互换。

17.两种#include调用区别

  • 对于#include<filename.h>,编译器先从标准库开始搜索filename.h。使得系统文件调用较快,只要向用户提供头文件和二进制的库即可;
  • 而对于#include”filename.h”,编译器先从用户的工作路径开始搜索filename.h,然后去寻找系统路径,使得自定义文件调用较快。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值