【常问基础】03.预处理
【嵌入式八股】一、语言篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM
【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym
【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM
【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0
03.预处理
头文件
51.# include< filename. h>和# include" filename. h"有什么区别?
对于 include< filename. h>,编译器先从标准库路径开始搜索 filename.h,使得系统文件调用较快。而 对于# include“ filename.h"”,编译器先从用户的工作路径开始搜索 filename.h,然后去寻找系统路径,使得自定义文件较快。
52.头文件的作用有哪些?
C头文件是包含函数原型、宏、类型定义等C语言程序元素的文本文件,可以被其他源代码文件引用。头文件通常包含在一个源代码文件中,以便其他源代码文件可以使用其中定义的函数和变量。
头文件的主要作用如下:
- 声明和定义函数:头文件可以包含函数原型和定义,以便其他源代码文件可以使用这些函数。
- 定义常量和宏:头文件可以包含常量和宏的定义,以便其他源代码文件可以使用这些常量和宏。
- 定义结构和类型:头文件可以包含结构和类型的定义,以便其他源代码文件可以使用这些结构和类型。
- 保护代码:头文件可以使用预处理指令
#ifndef
、#define
和#endif
来防止头文件被重复包含。 - 模块化:头文件可以帮助将程序分成逻辑上独立的模块,提高代码的可读性和可维护性。
- 跨平台移植:头文件可以根据不同的平台和操作系统提供不同的实现,以便在不同的系统上运行。
C标准库中的头文件包括stdio.h
、stdlib.h
、string.h
等等。除了C标准库的头文件之外,还有许多其他的头文件,比如math.h
、time.h
、ctype.h
等等。
53.在头文件中定义静态变量是否可行,为什么?
可以通过编译,但是使用static定义变量证明该变量的作用域范围仅在该源文件内,其他源文件不能访问。如果在头文件中定义static变量,证明包含了所有这个头文件的源文件都定义了该变量,会造成变量多次定义浪费内存,而且不是真正的全局变量。
54.如何避免头文件重复引入和重复定义
防止头文件重复引入
使用预编译指令
//条件编译
#define // 宏定义
#undef // 取消宏
#include // 文本包含
#ifdef // 如果宏被定义就进行编译
#if defined // 与ifdefine的区别在于可以组成复杂的判别条件
#ifndef // 如果宏未被定义就进行编译
#if !defined // 与if !define的区别在于可以可以组成复杂的判别条件
#endif // 结束编译块的控制
#if defined // 表达式非零就对代码进行编译
#else // 作为其他预处理的剩余选项进行编译
#elif // 这是一种#else和#if的组合选项
#elif defined // 与ifdefine的区别在于可以可以组成复杂的判别条件
#elif !defined // 与ifdefine的区别在于可以可以组成复杂的判别条件
//编译指令
#line // 改变当前的行数和文件名称
#error // 输出一个错误信息
#pragma // 为编译程序提供非常规的控制流信息,可跟once,message等许多参数。
- 使用条件编译指令
#ifndef XXXX_H
#define XXXX_H
......
#endif
优点:
不光可以保证同一个文件不被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不被同时引入。 受C/C++语言标准的支持,不受编译器的任何限制
缺点:
如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况——这种情况有时非常让人抓狂。 由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,条件编译指令会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式。
- 使用pragma once指令
#pragma once
pragma once编译指令使得同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。
优点:
你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。
遇到已经引入过的头文件时会直接跳过,而不需要打开。因此大型项目的编译速度也因此提高了一些。
缺点:
#pragma once方式却不受一些较老版本的编译器支持,一些支持了的编译器又打算去掉它,所以它的兼容性可能不够好。
如果某个头文件有多份拷贝或者被多个.c或.h文件引入,pragma once不能保证他们不被重复引入。当然,相比宏名碰撞引发的“找不到声明”的问题,这种重复包含很容易被发现并修正。
- 两者混用
#pragma once
#ifndef XXXX_H
#define XXXX_H
……
#endif
防止
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇【本专栏】 2.计算机基础 3.硬件篇 4.嵌入式Linux (建议PC端查看)