(嵌入式八股)第1章 C语言(二)
1.11 const关键字
const
关键字在C语言中用于定义常量,它可以修饰局部变量、指针等,确保这些值在声明后的作用域内不能被修改。以下通过具体案例进行说明。
修饰局部变量:值不可修改
当const
修饰局部变量时,该变量的值一旦被赋值后就不能再修改。
a
被声明为const int
,这意味着a
是常量,在程序运行期间其值不允许被修改。- 如果取消注释
a = 20;
这一行,编译器会报错,因为常量的值不能更改。
修饰指针:常量指针与指针常量
常量指针
常量指针是指指针指向的内容是常量,即指针指向的值不能改变。但是,指针本身是可以改变的,可以指向其他的地址。
ptr
是一个常量指针,指向a
。- 虽然
ptr
可以指向不同的地址(如b
),但不能修改ptr
当前指向地址的内容,即不能修改*ptr
。 - 如果尝试通过
*ptr = 30;
来修改ptr
指向的值,将会导致编译错误。
指针常量
指针常量是指指针本身是常量,不能改变指向的地址,但可以修改地址中保存的数值。
ptr
是指针常量,指向a
。- 尽管
ptr
不能指向其他的地址(不能做ptr = &b;
),但是它可以修改a
的值(通过*ptr = 30;
)。 - 如果尝试修改
ptr
指向的地址,将导致编译错误。
总结
- 常量指针 (
int const *ptr
):指向的值不可修改,但指针本身可以指向其他地址。 - 指针常量 (
int *const ptr
):指针本身不可修改,始终指向相同的地址,但可以修改地址中的值。
1.12 const 和 #define的区别
起作用的阶段
const
是编译器的关键字,在编译阶段起作用。#define
是预处理器指令,在预处理阶段起作用。
解释:
const
在编译阶段由编译器处理,常量的值和类型会在编译时被解析和检查。#define
是预处理指令,在程序开始编译之前由预处理器进行文本替换,这意味着常量的值仅仅是通过替换文本的方式实现的,并不会进行类型检查。
类型
const
定义的常量有类型。#define
定义的常量没有类型。
解释:
const
必须在声明时指定类型,并且编译器会进行类型检查。例如,const int a = 10;
表明a
是一个int
类型的常量。#define
是纯粹的文本替换,例如,#define PI 3.14
,它不会关心类型,只会把PI
替换为3.14
,所以没有类型检查。
作用域
const
定义的常量具有作用域限制,可以根据声明位置的不同,作用域不同。#define
定义的常量没有作用域限制,整个程序中都有效。
const
常量的作用域受到其声明位置的影响,常常局限在当前的函数或块级作用域内。例如:
#define
常量在整个文件中有效,甚至在跨文件的情况下也会被替换。例如:
符号表
const
会生成符号表中的一个符号,具有明确的名字和类型,能够进行调试和符号查找。#define
不会生成符号表,也不会产生对应的符号。
解释:
const
常量在编译时生成一个符号,这使得常量可以在调试过程中使用调试器来跟踪和分析,并且可以进行符号查找。#define
常量只是预处理器的简单文本替换,不会生成符号表,也不容易在调试过程中进行跟踪。
使用 const
定义常量:
使用 #define
定义常量:
总结
const
关键字在编译时由编译器处理,定义的常量有类型,并且具有作用域限制,能够在调试时进行符号查找。#define
预处理指令在预处理阶段由预处理器处理,常量没有类型,作用域没有限制,且无法在调试时跟踪。
1.13 extern关键字
• 引用同一个文件中的变量:利用extern关键字,使用在后边定义的变量。
引用另一个文件中的变量或函数:说只有当一个变量是一个全局变量时,extern变量才会起作用
extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。
在 File1.c 中,我们使用 extern 关键字来定义一个全局变量 globalVar,并初始化为 10。
在 File2.c 中,我们使用 extern 关键字来声明同名的全局变量 globalVar,以表示它是在其他源文件中定义的。
然后,在 main 函数中,我们可以访问并打印 globalVar 的值。
1.14 #include<> 和 #include""的区别
查找的目录不同,使用场景不同
使用 #include<>:
• 编译器会先在系统的标准头文件目录中查找,如果找不到则报错。
• 一般用于包含系统头文件,诸如stdlib.h、stdio.h、iostream等
使用 #include"":
• 在当前源文件的相对路径或指定的绝对路径中寻找头文件。编译器会首先在当前源文件所在目录中查找,如果找不到再根据指定的路径查找。项目当前目录-》项目配置的头文件引用目录-》系统类库目录
• 用于包含用户自定义的头文件或项目中使用的其他非系统头文件。
注意:虽然#include""的查找范围更广,但是这并不意味着,不论是系统头文件,还是自定义头文件,一律用#include""包含。因为#include""的查找顺序存在先后关系,如果项目当前目录或者引用目录下存在和系统目录下重名的头文件,那么编译器在当前目录或者引用目录查找成功后,将不会继续查找,所以存在头文件覆盖的问题。另外,对于系统头文件,用#include<>包含,查找时一步到位,程序编译时的效率也会相对更高。
1.15 C语言的基本类型有哪些(32位系统),占用字节空间
数据类型 |
32位系统(字节) |
64位系统(字节) |
bool |
1 |
1 |
char |
1 |
1 |
unsigned char |
1 |
1 |
short int |
2 |
2 |
int |
4 |
4 |
指针 |
4 |
8 |
unsigned int |
4 |
4 |
float |
4 |
4 |
long |
4 |
8 |
unsigned long |
4 |
8 |
double |
8 |
8 |
long long |
8 |
8 |
位数和字节数
位数:处理器的位数(如32位)表示其数据总线的宽度,以及处理器一次能处理的二进制数据位数。 字节数:1字节(Byte)等于8位(Bit),是八位二进制,是两位16进制。 在32位处理器中,4字节正好等于32位,这与处理器的数据总线宽度一致,意味着处理器一次可以处理或传输4字节的数据。
字的定义
在计算机体系结构中,“字(word)”的长度通常与处理器的位数相对应。 对于32位处理器,1个字(word)通常等于32位或4字节。
1.16 头文件#ifndef/#define/#endif的作用
在C语言中,#ifndef
、#define
和 #endif
是用来防止头文件重复包含的常见方法,它们通常被称为 防止重复包含(Include Guard)。这些预处理指令的组合可以确保一个头文件在同一个源文件中只被包含一次,从而避免重复定义问题。
#i
(如果没有定义)
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与学习心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。