c高级常见笔试题
- 枚举与# define宏的区别有哪些?
枚举与宏的概述
(1) 枚举:是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内
(2) # define宏定义是用一个指定的标识符来代表一个字符串
枚举与# define宏的区别
(1) 在编译器中可以调试枚举变量,不能调试宏常量
(2) # define宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候才确定其值
(3) 枚举可以一次定义大量相关的常量,而# define宏一次只能定义一个
- 空结构体所占的内存是多少?
结构体所占内存大小是其成员所占内存之和
一个空结构体所占的内存是1字节
因为编译器认为任何一种数据都有自己的大小,这样用这样这个类型定义一个变量才能
分配正确的内存空间大小,在所有的数据类型中char占内存最小,为1字节。
- 枚举类型的优点
(1) 枚举常量相当于一个符号常量,因此具有见名知意的好处,可以增加程序的可读性
(2) 枚举类型的变量取值范围仅限于列出的枚举常量范围,若取值不在列出的范围内,系统会视为出错,这样可以帮助系统检查错误,降低程序的理解难度
(3) 枚举类型还便于系统对枚举变量进行类型检查,从而增强可安全性
- typedef与#define宏的相似之处与不同之处是什么?
(1) 相似之处
通常都可以理解为为一个字符起别名,在程序中用一个新的字符代替原有的字符
(2) 区别
a. 实质含义不同,# define是字符串替换,typedef是为类型起了一个别名
b. 宏定义的句尾没有分号作为结束标志,其本身并不在编译过程中进行,而是在预处理过程中就已经完成了很难发现潜在的错误
#define INT int*
typedef int* my_intp;
INT i, i_p; ==> int* i, i_p;
my_intp a, ap;
-
大小端模式对union类型数据有什么影响
大小端模式
(1) 大端模式存储:高位数据存放在低地址中
(2) 小端模式存储:高位数据存放在高地址中
大小端模式对共用体类型数据的影响
Union型数据所占的内存等于其最大的成员所占的内存,对union型的成员的存取都是相对于该联合体基地址的偏移量为0处开始,也就是说联合体的访问无论对哪个变量的存取都是从union的首地址位置开始,因此大小端模式的存储将会直接影响union成员的值。 -
如何证明联合体变量的所有成员是共享一个内存单元的?
声明一个联合体类型有两个成员变量,一个是int型的数组,另一个是char型的数组,先按照其中一个int型数组成员赋值,然后按照另一个char型数组成员输出。若整型数组与字符数组是共享一个内存的,那么输出的内容与写入的内容应该是一致的,否则结果不一致。
- 字节对齐的问题
什么是字节对齐?
计算机中内存大小的基本单位是字节(byte),理论上来讲,可以从任意地址访问某种基本数据类型,但是实际上,计算机并非逐字节大小读写内存,而是以2,4,或8的倍数的字节块来读写内存,如此一来就会对基本数据类型的合法地址作出一些限制,即它的地址必须是2,4或8的倍数。那么就要求各种数据类型按照一定的规则在空间上排列,这就是对齐。===》通常32位的系统或者mcu是4字节对齐。
对齐准则是什么?
- 结构体变量的首地址能够被其对齐字节数大小所整除。
- 结构体每个成员相对结构体首地址的偏移都是成员大小的整数倍,如不满足,对前一个成员填充字节以满足。
- 结构体的总大小为结构体对齐字节数大小的整数倍,如不满足,最后填充字节以满足。
#include<stdio.h>
#include<stdint.h>
struct test
{
int a;
char b;
int c;
short d;
};
int main(int argc,char *argv)
{
printf("the size of struct test is %d\n",sizeof(struct test));
return 0;
}
运行结果:
the size of struct test is 16
换一种定义方法
#include<stdio.h>
#include<stdint.h>
struct test
{
int a;
int c;
char b;
short d;
};
int main(int argc,char *argv)
{
printf("the size of struct test is %d\n",sizeof(struct test));
return 0;
}
运行结果:
the size of struct test is 12
结论:在设计结构的时候,合理调整成员的位置,可以大大节省存储空间
为什么要字节对齐?
提高内存系统性能
跨平台编程
可以使用#pragma pack(n),使得结构间一字节对齐
#pragma pack(1) /*1字节对齐*/
struct test
{
int a;
char b;
int c;
short d;
};
总结:
- 结构体成员合理安排位置,以节省空间
- 跨平台数据结构可考虑1字节对齐,节省空间但影响访问效率
- 跨平台数据结构人为进行字节填充,提高访问效率但不节省空间
- 本地数据采用默认对齐,以提高访问效率
- 如下的makefile中,执行make后终端的打印结果是什么
all:cd ef
@echo 123
cd:
@echo 456
ef:
@echo 789
答案:
456
789
123
- 如下的makefile中,执行make后终端的打印结果是什么
Makefile
x := foo
y := $(x)b
x := new
.PHONY : test
test :
@echo "x => $(x)"
@echo "y => $(y)"
结果:
x => new
y => foob
Makefile
x = foo
y = $(x)b
x = new
a = $(b)
b = $(c)
c = hello-makefile
.PHONY : test
test :
@echo "x => $(x)"
@echo "y => $(y)"
@echo "a => $(a)"
@echo "b => $(b)"
@echo "c => $(c)"
结果:
x => new
y => newb
a => hello-makefile
b => hello-makefile
c => hello-makefile
Makefile
x := foo
y := $(x)b
x ?= new
.PHONY : test
test :
@echo "x => $(x)"
@echo "y => $(y)"
结果:
x => foo
y => foob
Makefile
x := foo
y := $(x)b
x += new
.PHONY : test
test :
@echo "x => $(x)"
@echo "y => $(y)"
结果:
x => foo new
y => foob
总结:
简单赋值 (:=)
递归赋值 ( = )
条件赋值( ?= )
追加赋值( += )
- 如下的Makefile中,执行make后终端的显示结果是
Makefile
```makefile
.PHONY : all first second third
all : first second third
@echo "\$$@ => $@"
@echo "$$^ => $^"
@echo "$$< => $<"
```
结果:
```
$@ => all
$^ => first second third
$< => first
```
总结:
&@ 当前规则中触发命令被执行的目标
&^ 当前规则中所有的依赖
&< 当前规则中第一个依赖
应用:
```makefile
CC := gcc
TARGET := hello-world.out
$(TARGET) : func.o main.o
$(CC) -o $@ $^
func.o : func.c
$(CC) -o $@ -c $^
main.o : main.c
$(CC) -o $@ -c $^
.PHONY : rebuild clean all
rebuild : clean all
all : $(TARGET)
clean :
rm *.o $(TARGET)
```