五、预处理
预处理也成为预编译,它为编译做预备工作,主要进行代码文本的替换工作,用于处理#开头的指令,其中预处理器产生编译器的输出。
1、C/C++ 头文件中的ifndef /define /endif 的作用有哪些?
如果一个项目中存在两个C文件,而这两个C文件都include了同一个头文件,当编译时,这两个C文件要一同编译成一个可运行文件,可能会产生大量的声明冲突。而解决的办法是把头文件的内容都放在#ifndef 和#endif 中。
2、#include <filename.h> 和 #include "filename.h"有什么区别
对于#include <filename.h>,编译器先从标准库路径开始搜索filename.h, 使得系统文件调用较快。而对于 #include "filename.h",编译器先从用户的工作路径开始搜索,然后去寻找系统路径,使得自定义文件较快。
3、#define 有哪些缺陷
由于宏定义在预处理阶段进行,主要做的是字符替换工作,存在的缺陷:
a、它无法进行类型检查
b、由于优先级不同,使用宏定义时,可能会存在副作用。如#define ADD(a,b) a+b 就会存在问题,需要加括号。
c、无法单步调试。
d、会导致代码膨胀
e、在C++中,使用宏无法操作类的私有数据成员。
4、如何使用define 声明一个常数,用以表明 1 年有多少秒 (忽略闰年问题)
#define SECOND_PER_YEAR (60*60*24*365)UL (考虑到溢出,所以使用长整型)
5、含参数的宏与函数有什么区别
含参数的宏有时完成的是函数实现的功能,但是并非所有的函数都可以被含参数的宏所替代。
两者的特点:
a、函数调用时,首先求出实参表达式的值,然后代入形参。而使用带参的宏只是进行简单的字符替换。
b、函数调用是在程序运行时处理的,它需要分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,也不进行值的传递处理,也没有“返回值”的概念。
c、对函数中的实参和形参都要定义类型。两者的类型要求一致,如果不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时代入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
d、调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
e、使用宏次数多时,宏展开后源程序会变得很长,因为每展开一次都使得程序内容增长,而函数调用不使源程序变长。
f、宏替换不占用运行时间,而函数调用则占运行时间。
g、参数每次用于宏定义时,它们都将重新求值,由于多次求值,具有副作用的参数可能会产生不可预料的结果。而函数调用则不会
一般来说,用宏来代替简短的表达式比较合适。
6、宏定义平方运算#define SQR(X) X*X 是否正确
不正确,会造成错误。
7、不能使用大于、小于、if 语句,如何定义一个宏来比较a、b 的大小
#define MIN(A,B) ((A) <= (B) ? (A): (B))
8、如何判断一个变量是有符号还是无符号数
有三种方法:
a、采用取反操作
b、无符号数和有符号数相减的结果为无符号数。
c、通过改变符号位判断。
9、#define TRACE(S) (printf(“%S\n”,#S),S) 是什么意思
#进行宏字符串连接,在宏中把参数解释为字符串,不可以在语句中直接使用。
10、不使用sizeof ,如何求int 占用的字节数
采用地址值相减。
11、如何使用宏求结构体的内存偏移地址(不会)
#define OffSet(type, field) ((size_t)&((type *)0-> field))[具体的解释百度]
12、如何用sizeof 判断数组中有多少个元素
用整个数组的sizeof 去除以一个元素的sizeof 即可。
13、枚举和define 有什么区别
区别很小。
在C语言中,枚举为整型,枚举常量为 int 型。
具体区别:
a、枚举常量是实体中的一种,而宏定义不是实体
b、枚举常量属于常量,但宏定义不是常量。
c、枚举常量具有类型,但宏定义没有类型,枚举变量具有普通变量相同的性质,但宏没有。
d、#define 宏常量是在预编译阶段进行简单的值替换,枚举常量则是在编译的时候确定其值。
e、一般在编译器里可以调试枚举变量,但宏常量不行。
f、枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。
14、typedef 的define 有什么区别
区别:
a、原理不同。#define 是预处理指令,不做正确性检查;typedef 是关键字,有类型检查功能。
b、功能不同。typedef 用来定义类型的别名,是类型易于记忆。而#define 不只是取别名,还可以定义常量、变量、编译开关等。
c、作用域不同。#define 没有作用域限制;而typedef 有自己的作用域。
d、对指针的操作不同。作用不同。
15、C++ 中宏定义与内联函数有什么区别
宏代码本身不是函数,但使用起来却像函数,预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用,返回参数,执行return等过程,从而提高速度。
内联函数是代码被插入到调用者代码处的函数。内联函数也不是万能的,它的使用是有所限制的,它只适合函数体内简单的函数使用,不能包含复杂的结构和控制语句(如for while switch),并且内联函数本身不能直接调用递归函数(自己内部还调用自己的函数)。
两者的区别:
a、宏定义是在预处理阶段进行代码替换,而内联函数是在编译阶段插入代码;
b、宏定义没有类型检查,而内联函数有类型检查。
内联函数与普通函数的最大区别:在于其内部的实现方式上,普通函数在调用时有寻址过程,而内联函数不需要寻址。
16、定义常量谁更好?#define 还是const
效果虽然一样,但侧重点不同。
define 既可以替代常数值,又可以替代表达式,甚至是代码段,但容易出错;
const 的引入可以增强程序的可读性,使程序维护与调试更加方便。
主要区别:
a、define 只是用来进行单纯的文本替换,define的生命周期止于编译期,不分配内存空间,它存在于程序的代码段,在实际程序中,它只是一个常数,一个命令中的参数并没有实际存在;而const 常量存在于程序的数据段,并在堆栈中分配了空间,const 常量在程序中确确实实地存在,并且可以被调用和传递。
b、const 常量有数据类型,而 define 常量没有数据类型。
c、很多IDE 支持调试const定义的常量,而不支持define 定义的常量、\。
六、结构体与类
1、C语言中struct 和union 的区别是什么
struct (结构体)与union (联合体)是C语言中两种不同的数据结构。
区别:
a、联合体中所有成员共用一块地址空间,联合体的长度为其最长的成员的长度;而结构体中所有成员占用空间是累加的(需要考虑字节对齐)
b、对于联合体的不同成员赋值,将会对它的其它成员重写,而对结构体就不会。
2、C 和C++ 中struct 的区别是什么
C语言中struct 与C++ 中的struct 区别表现在以下三个方面:
a、C语言的struct 不能有函数成员,而C++ 的struct 可以有;
b、C语言的struct 中数据成员没有private、public和protected 访问权限的设定,而C++的struct 的成员有访问权限的设定。
c、C语言的struct 是没有继承关系的,而C++ 的struct 却有丰富的继承关系。
3、C++ 中struct 与class的区别是什么
如果没有多态和虚拟继承,在C++中,struct 和class 的存取效率完全相同。
两点区别:
a、默认继承权限,class 继承默认是private 继承,而struct 继承默认是 public 继承
b、class 还用于定义模板参数,就行typename, 但关键字struct 不用于定义模板参数。
七、位操作
1、一些结构声明中的冒号和数字是什么意思
C语言的结构体可以实现位段,它的定义形式是在一个定义的结构体成员后面加上冒号,然后是该成员所占的位数。位段的结构体必须是int 或者unsigned int 类型,不能是其他类型。
2、最有效的计算 2 乘以 8 的方法是什么
2<<3
3、如何实现位操作求两个数的平均值
(x & y) + ((x^y)>> 1)
(x & y)表示的是取出 x 与 y 二进制位数中都为 1 的所有位
(x^y)表示的是x 与 y 中有一个为 1 的所有位,右移一位相当为执行除以2运算。
4、unsigned int i = 3; printf(“%u\n”, i *-1)输出多少
4294967293,。 无符号的int值域为[0,4294967295]。
5、如何求解整型数的二进制表示中1 的个数
while(x){ countx++; x=x&(x-1)}
6、不能用sizeof,如何判断操作系统是16位还是32 位的
打印最大值,或者对0取反。
7、嵌入式编程中,什么是大端?什么是小端
大端模式:低地址存放高字节,高地址存放低字节
小端模式:低地址存放低字节,高地址存放高字节
8、考虑n 位二进制数,有多少个数中不存在两个相邻的1
满足斐波拉契数列
9、不用除法操作符如何实现两个正整数的除法
位运算的知识:
a、常用的等式:-n = ~(n-1) = ~n + 1
b、获取整数n 的二进制中 最后一个 1:n&(-n) 或者 n&~(n-1)。例如, n=010100,则-n = 101100,n&(-n) =000100。
c、去掉整数n 的二进制中 最后一个 1:n&(n-1) 。例如, n=010100,则n-1 =010011,n&(n-1) =010000。
采用减法;采用移位操作。