热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

常见嵌入式面试题之C语言篇——第1期

常见嵌入式面试题之C语言篇——第1期前言第1期问题:1.关键字static的作用2.关键字const是什么含意3.关键字volatile有什么含意,并给


常见嵌入式面试题之C语言篇 ——第1期

    • 前言
    • 第1期问题:
      • 1.关键字static的作用
      • 2.关键字const是什么含意
      • 3.关键字volatile有什么含意,并给出三个不同的例子
      • 4.引用与指针的区别是什么
      • 5. .h头文件中的ifndef/define/endif 的作用
      • 6.全局变量和局部变量在内存的区别
      • 7.数组与链表的区别
      • 8.堆栈溢出一般是由什么原因导致的
      • 9. C/C++中的内存分配
      • 10.不能做switch()参数的数据类型
      • 11.局部变量能否和全局变量重名
      • 12.如何引用一个已经定义过的全局变量
      • 13.全局变量可不可以定义在可被多个.C文件包含的头文件中,为什么
      • 14.static 全局变量、局部变量、函数与普通全局变量、局部变量、函数的区别
      • 15.什么是预编译,何时需要预编译
      • 16.结构与联合有和区别
      • 17.请说出const与#define 相比,有何优点
      • 18.简述数组与指针的区别
      • 19论述含参数的宏与函数的优缺点
      • 20.访问固定的内存位置(Accessing fixed memory locations)
    • 总结


前言

本博客旨在分享学习过程中整理过的相关知识,主要涉及C语言、C++及嵌入式相关问题。若涉及引用未注明出处的部分请及时私信或评论。博客内容有误的部分也会及时勘正,最后如有幸得到转载请注明出处~谢谢支持!


第1期问题:


1.关键字static的作用

在C语言中,static主要用于定义全局静态变量、局部静态变量以及静态函数。
全局静态变量 :在全局数据区内分配内存,作用域只在定义的本文件内可见,生存周期直到程序运行结束。
局部静态变量:在全局数据区分配内存,作用域只在定义的本模块内可见,存周期直到程序运行结束。
静态函数:只能在本源文件中使用,如果在其他文件中存在同名函数,两者互不干扰。
在C++中新增两种作用:定义静态数据成员或静态函数成员。
静态数据成员必须在类外定义及初始化,静态函数不能访问非静态数据成员


2.关键字const是什么含意

浅显理解:只读
(1)const int a;
(2)int const a;
(3)const int *a;
(4)int * const a;
(5)int const * a const;
其中(1)(2)作用是一样,a是一个常整型数。(3)意味着a是一个指向常整型数的指针(整型数是不可修改的,但指针可以)。(4)的意思a是一个指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的)。(5)中a是一个指向常整型数的常指针(指针指向的整型数是不可修改的,同时指针也是不可修改的)。
保护某些重要的地址和数据,给读代码的人传递信息,防止代码无意被修改
1). 关键字const的作用是为给读你代码的人传达非常有用的信息
2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现


3.关键字volatile有什么含意,并给出三个不同的例子

答:不进行编译器优化,程序在每次用到这个变量时都会重新读取,而不是用保存在寄存器里的备份
1).并行设备的硬件寄存器(如:状态寄存器)
2).一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3).多线程应用中被几个任务共享的变量

1.一个参数既可以是const还可以是volatile吗?解释为什么。
volatile修饰符告诉complier变量值可以以任何不被程序明确指明的方式改变,最常见的例子就是外部端口的值,它的变化可以不用程序内的任何赋值语句就有可能改变的,这种变量就可以用volatile来修饰,complier不会优化掉它。 const修饰的变量在程序里面是不能改变的,但是可以被程序外的东西修改,比如外部端口的值,如果仅仅使用const,编译器可能会优化掉这些变量,加上volatile就不会有问题。
2.一个指针可以是volatile 吗?解释为什么。
因为指针和普通变量一样,有时也有变化程序的不可控性。常见例:中断服务子程序修改一个指向一个buffer的指针时,必须用volatile来修饰指针。


4.引用与指针的区别是什么

引用必须被初始化,指针不必。
引用初始化以后不能被改变,指针可以改变所指的对象。
不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。


5. .h头文件中的ifndef/define/endif 的作用

防止该头文件被重复引用。


6.全局变量和局部变量在内存的区别

全局变量储存在静态数据区,局部变量在堆栈中。
全局变量的生命周期是整个程序运行期间,局部变量的生命周期是声明该变量的函数区间。


7.数组与链表的区别

数组是一块连续的内存区间、大小固定,数据只能连续存储。
链表可以是一块连续的内存区间也可以是不连续的内存区间,大小不固定,数据可以随机存储。


8.堆栈溢出一般是由什么原因导致的

1)函数调用层次太深。函数递归调用时,系统要在栈中不断保存函数调用时的现场和产生的变量,如果递归调用太深,就会造成栈溢出,这时递归无法返回。当函数调用层次过深时也可能导致栈无法容纳这些调用的返回地址而造成栈溢出。
2)动态申请空间使用之后没有释放。由于C语言中没有垃圾资源自动回收机制,因此,需要程序主动释放已经不再使用的动态地址空间。申请的动态空间使用的是堆空间,动态空间使用不会造成堆溢出。
3)数组访问越界。C语言没有提供数组下标越界检查,如果在程序中出现数组下标访问超出数组范围,在运行过程中可能会内存访问错误。
4)指针非法访问。指针保存了一个非法的地址,通过这样的指针访问所指向的地址时会产生内存访问错误。


9. C/C++中的内存分配

在C/C++中内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。通常32位Linux内核虚拟地址空间划分03G为用户空间,34G为内核空间,Linux进程地址空间分布如下图所示:


栈区(stack):由编译器在需要的时候分配,函数执行时,形参及局部变量(不包括static声明的变量)分配在栈区,函数运行结束后,内存自动释放。属于动态内存分配
堆区(heap):存放进程运行中被动态分配的内存段,由程序员手动分配释放。如果申请的内存没有被释放,则程序运行结束由系统自动回收。在C语言中,通过malloc或calloc、realloc、free函数申请、释放内存。**属于动态内存分配
全局/静态存储区(.data段):已初始化的全局变量(包括全局静态变量)和局部静态变量,程序运行结束后由系统释放。属于静态内存分配。
常量存储区(.rodata段):包含全局常量、const修饰的全局变量及字符串常量,const修饰的局部变量仍然在栈区。属于静态内存分配。
代码段(.text段):存放程序的二进制代码。

补充:BSS段(Block Started by Symbol):存放程序中未初始化的全局变量及初始化为0的全局变量。属于静态内存分配。
动态链接库映射区:如果程序调用了动态链接库,则会该部分。该区域用于映射装载的动态链接库。
保留区:内存中受到保护而禁止访问的内存区域。


10.不能做switch()参数的数据类型

答:除浮点型(单精度float,双精度double)、字符串类型(string)以外均可。C/C++中支持byte,char,short,int,long,bool,整数类型和enum(枚举)类型,不支持float,double,string。


11.局部变量能否和全局变量重名

答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。


12.如何引用一个已经定义过的全局变量

答 :可以用引用头文件的方式,也可以用extern关键字。如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。


13.全局变量可不可以定义在可被多个.C文件包含的头文件中,为什么

答 :可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时链接不会出错。


14.static 全局变量、局部变量、函数与普通全局变量、局部变量、函数的区别

静态全局变量的作用域:只在定义该变量的源文件内有效
static函数与普通函数作用域不同,加上static只能在当前源文件说明和定义。
static全局变量与普通的全局变量区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。


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

答:预编译又称为预处理,是做些代码文本的替换工作。#define宏定义的替换,条件编译等。


16.结构与联合有和区别

(1)结构和联合都是由多个不同的数据类型成员组成, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。
(2)对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。


17.请说出const与#define 相比,有何优点

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


18.简述数组与指针的区别

答:数组在静态存储区被创建(如全局数组),或者在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,更加灵活。


19论述含参数的宏与函数的优缺点

1.函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。
2.宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
3.宏定义时,可以是任何类型的数据。对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。


20.访问固定的内存位置(Accessing fixed memory locations)

嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;//先取出地址的值付给指针
*ptr = 0xaa66; //再把指针解引用


总结

近期会整理嵌入式面试相关问题,包含C语言、C++以Linux操作系统。之后会陆续更新基于以上三部分内容中的重点问题进行深入解析与探讨。
如果博客内容有不严谨或错误的部分,请及时评论或私信,本人将第一时间进行补充与更正!
还请广大网友不吝赐教~共同加油!


推荐阅读
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
author-avatar
caiyafang4376
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有