(嵌入式八股)No.1 C语言(1)
写在前面,在嵌入式软件面试中,面试官会问你使用哪个编程语言更多一点?C or C++?其实在嵌入式中用C多一点,那么接下来你要重点掌握关键字的作用及其原理,然后就是指针,位运算等,还有内存管理,排序算法最好也了解一下,毕竟有的面试官直接让你手撕快排!
1.1 static(建议不仅要知道用法还要知道原理)
static关键字有多种用途,主要用于控制变量和函数的作用域和存储期。
它主要有三种常见使用场景:
void foo(void) {
static int count = 0;
count++;
printf("count = %d\n", count);
}
应用: 限制全局变量的可见性(“封装”全局变量) 避免命名冲突 // file1.c static int g_val = 10; // 仅 file1.c 内可见 // file2.c static int g_val = 20; // 与 file1.c 的 g_val 无冲突
static void helper(void) {
// 仅在本文件可见
}
总结:
a.修饰局部变量
b.修饰全局变量
c.修饰函数
1.2 const(C中的变量:局部,函数形成,返回值,指针)
const 是 C 语言中一个非常常见但容易混淆的关键字,它用于定义只读对象(read-only object),也常与指针结合使用。
Const的基本用法:
1.修饰变量
const int a = 100; // a 是常量,值不能被修改 // a = 200; // 错误:a 是常量,不能被修改 说明:const 修饰的变量在初始化后,其值不能被修改。
2.修饰函数参数
void func(const int x) {
// x = 200; // 错误:x 是常量,不能被修改
}
说明:const 修饰函数参数,表示函数体内不能修改该参数的值。这通常用于防止函数意外修改参数值。
3.修饰函数返回值
const char* getstr() {
return "Hello, World!"; // 返回的是字符串常量
}
说明:const 修饰函数返回值,表示返回值不能被修改。这通常用于返回字符串常量或其他不可修改的对象。
4.修饰指针(务必掌握)
1.常量指针:指针指向的内容不能修改,但指针的地址可以修改。 const int* a; // 等同于 int const* a; const int b = 100; const int* a = &b; // *a = 200; // 错误:a 指向的内容不能修改 a = &b; // 正确:a 的地址可以修改 说明:int* const a 表示 a 的地址是常量,不能修改 a 的地址。 2.指针常量:指针的地址不能修改,但指针指向的内容可以修改。 int* const a; int b = 100; int* const a = &b; *a = 200; // 正确:a 指向的内容可以修改 // a = &b; // 错误:a 的地址不能修改 说明:int* const a 表示 a 的地址是常量,不能修改 a 的地址。 3.常量指针常量:指针的地址和指向的内容都不能修改。 const int* const a; const int b = 100; const int* const a = &b; // *a = 200; // 错误:a 指向的内容不能修改 // a = &b; // 错误:a 的地址不能修改 说明:const int* const a 表示 a 的地址和指向的内容都是常量,都不能被修改。
形式 |
含义 |
可改内容 |
const int *p 或 int const *p |
常量指针(pointer to const) |
✅ 指针可改❌ 所指内容不可改 |
int * const p |
指针常量(const pointer) |
❌ 指针不可改✅ 所指内容可改 |
|
指向常量的常指针 |
❌ 都不可改 |
1.3 const 和 #define的区别(了解即可)
1.#define 是一个预处理指令,用于定义宏(macro)。宏是一种简单的文本替换机制,它在编译之前由预处理器(preprocessor)处理。#define 可以用于定义常量、函数宏以及条件编译指令。
类别 |
示例 |
功能 |
对象宏 |
|
定义常量 |
函数宏 |
|
实现简单函数替代(注意括号的重要性!!!) |
条件宏 |
|
控制编译行为 |
字符串化 |
|
参数转字符串 |
拼接 |
|
拼接标识符 |
系统宏 |
|
获取编译信息 |
2.二者区别
特性 |
|
|
处理阶段 |
预处理阶段(文本替换) |
编译阶段 |
是否分配内存 |
否 |
是 |
是否有类型 |
否 |
有类型 |
是否可调试(在符号表中) |
否 |
是 |
是否可作用域控制 |
否(全局有效) |
是 |
调试安全性 |
低 |
高 |
3.使用 #define 定义常量
#include <stdio.h>
#define MAX_VALUE 100 // 使用宏定义一个常量 MAX_VALUE,值为 100
// 这是一个简单的文本替换,没有类型,作用域是整个文件
int main() {
int value = MAX_VALUE; // 将 MAX_VALUE 的值赋给变量 value
// 在预处理阶段,MAX_VALUE 会被替换为 100
printf("The value is: %d\n", value); // 打印变量 value 的值
return 0; // 程序正常结束
}
4.使用const定义常量
#include <stdio.h>
const int MAX_VALUE = 100; // 使用 const 定义一个常量 MAX_VALUE,值为 100
// 这是一个有类型的常量,类型为 int,作用域取决于定义位置
// 如果定义在函数外部,它是全局常量;如果定义在函数内部,它是局部常量
void MofConst()
{
const int MIN_VALUE = 10; //注意如果在函数内部定义的局部变量后面是无法访问到的。
}
int main() {
int value = MAX_VALUE; // 将 MAX_VALUE 的值赋给变量 value
// MAX_VALUE 是一个实际的变量,有内存分配
printf("The value is: %d\n", value); // 打印变量 value 的值
return 0; // 程序正常结束
}
5.const修饰的变量存放位置
对于const修饰的局部变量:存放在栈中,代码结束就会释放,在C语言中可以通过指针修改里面的值。
对于const修饰的全局变量(已初始化的)存放在只读数据段,不可以通过指针修改里面的值,未出示化的存放在.bss。
1.4 volatile(编译优化阶段)
它在嵌入式开发、驱动编程、RTOS 等场景中尤为关键,因为它直接影响编译器优化行为。volatile表示“易变的”,告诉编译器:这个变量的值随时可能发生变化,不能对它进行优化。
使用场景:
情况 |
示例 |
外设寄存器(硬件自动修改) |
|
中断服务程序修改的变量 |
|
多线程共享变量 |
RTOS / 多核系统中的全局标志位 |
内 |
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
从入门到上岸,一站式搞定求职! 本硕纯机械,无竞赛无论文,后转行嵌入式软件开发(因为课题组师哥转嵌入式拿到30Woffer之后狠狠心动),秋招最终收获35W+offer可以为27届或者28届的的UU们提供参考,可以关注一下!!!
