c高级常见笔试题

c高级常见笔试题

  1. 枚举与# define宏的区别有哪些?

枚举与宏的概述
(1) 枚举:是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内
(2) # define宏定义是用一个指定的标识符来代表一个字符串

枚举与# define宏的区别
(1) 在编译器中可以调试枚举变量,不能调试宏常量
(2) # define宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候才确定其值
(3) 枚举可以一次定义大量相关的常量,而# define宏一次只能定义一个

  1. 空结构体所占的内存是多少?

结构体所占内存大小是其成员所占内存之和
一个空结构体所占的内存是1字节
因为编译器认为任何一种数据都有自己的大小,这样用这样这个类型定义一个变量才能
分配正确的内存空间大小,在所有的数据类型中char占内存最小,为1字节。

  1. 枚举类型的优点

(1) 枚举常量相当于一个符号常量,因此具有见名知意的好处,可以增加程序的可读性
(2) 枚举类型的变量取值范围仅限于列出的枚举常量范围,若取值不在列出的范围内,系统会视为出错,这样可以帮助系统检查错误,降低程序的理解难度
(3) 枚举类型还便于系统对枚举变量进行类型检查,从而增强可安全性

  1. 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;
  1. 大小端模式对union类型数据有什么影响

    大小端模式
    (1) 大端模式存储:高位数据存放在低地址中
    (2) 小端模式存储:高位数据存放在高地址中
    大小端模式对共用体类型数据的影响
    Union型数据所占的内存等于其最大的成员所占的内存,对union型的成员的存取都是相对于该联合体基地址的偏移量为0处开始,也就是说联合体的访问无论对哪个变量的存取都是从union的首地址位置开始,因此大小端模式的存储将会直接影响union成员的值。

  2. 如何证明联合体变量的所有成员是共享一个内存单元的?

声明一个联合体类型有两个成员变量,一个是int型的数组,另一个是char型的数组,先按照其中一个int型数组成员赋值,然后按照另一个char型数组成员输出。若整型数组与字符数组是共享一个内存的,那么输出的内容与写入的内容应该是一致的,否则结果不一致。

  1. 字节对齐的问题

什么是字节对齐?

计算机中内存大小的基本单位是字节(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字节对齐,节省空间但影响访问效率
  • 跨平台数据结构人为进行字节填充,提高访问效率但不节省空间
  • 本地数据采用默认对齐,以提高访问效率
  1. 如下的makefile中,执行make后终端的打印结果是什么
all:cd ef
	@echo 123
cd:
	@echo 456
ef:
	@echo 789

​ 答案:

456
789
123
  1. 如下的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
    
    
    

    总结:

    ​ 简单赋值 (:=)

    ​ 递归赋值 ( = )

    ​ 条件赋值( ?= )

    ​ 追加赋值( += )

  2. 如下的Makefile中,执行make后终端的显示结果是

    Makefile

    .PHONY : all first second third 
      
    all : first second third
    	@echo "\$$@ => $@"
    	@echo "$$^ => $^"
    	@echo "$$< => $<"
    
    
    

    结果:

    $@ => all
    $^ => first second third
    $< => first
    
    
    

    总结:

    ​ &@ 当前规则中触发命令被执行的目标

    ​ &^ 当前规则中所有的依赖

    ​ &< 当前规则中第一个依赖

    应用:

    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)
    
    	
    
    

猜你喜欢

转载自blog.csdn.net/weixin_48430195/article/details/108737875