服务端2月18日 17:16
C语言位域(bit-field)有什么用?和位运算比哪个好?位域(bit-field)让你在结构体里按位定义成员,指定每个成员占几个二进制位。主要用途是压缩存储——当多个标志位只需要 0/1 时,用位域把多个 bool 塞进一个 int 里,省内存。在网络协议解析和硬件寄存器映射中非常常见。
## 追问
### 位域怎么定义?占多少内存?
```c
struct Flags {
unsigned int read : 1; // 1 bit
unsigned int write : 1; // 1 bit
unsigned int execute : 1; // 1 bit
unsign...服务端2月18日 17:17
C语言可变参数函数是怎么实现的?va_list 原理是什么?可变参数函数就是参数个数不固定的函数,最典型的例子是 `printf`。C 语言通过 `<stdarg.h>` 里的四个宏来操作可变参数:`va_list` 声明参数指针,`va_start` 定位到第一个可变参数,`va_arg` 逐个取出参数,`va_end` 收尾清理。
## 追问
### va_list 的底层原理是什么?
函数参数从右往左压栈,所以最后一个固定参数的地址紧挨着第一个可变参数。`va_list` 本质上是 `char*` 指针,`va_start` 根据最后一个固定参数的地址加上它的偏移量,算出第一个可变参数的位置。`va_arg` 取出当前参数后,指针按类...服务端2月18日 17:17
C语言 static 关键字有什么用?修饰变量和函数分别什么效果?static 在 C 语言里有三个作用:修饰局部变量让它持久化、修饰全局变量限制作用域、修饰函数限制可见性。记住一个规律——static 总是在"收窄"什么:局部变量收窄不了作用域(已经最窄了),就延长生命周期;全局变量和函数收窄可见范围到当前文件。
## 追问
### static 局部变量和全局变量有什么区别?
存储位置一样,都在 .data 或 .bss 段,生命周期都是程序运行全程。区别在作用域:static 局部变量只在函数内可见,全局变量整个文件可见。换句话说,static 局部变量就是"只有这个函数能用的全局变量"。
```c
int* get_counter() ...服务端2月18日 17:18
C语言 extern 关键字有什么用?跨文件共享变量怎么做?extern 告诉编译器"这个变量/函数在别的地方定义了,别报错,链接时再找"。核心作用就是跨文件共享变量和函数声明。
## 追问
### extern 声明和定义有什么区别?
定义分配内存,声明只是说"有这个东西"。一个变量在整个程序里只能定义一次,但可以声明多次:
```c
extern int count; // 声明:不分配内存,告诉编译器 count 在别处定义
int count = 0; // 定义:分配内存
```
常见坑:`extern int x = 10;` 虽然语法合法,但一旦在头文件里这么写,多个源文件 include 后就会重复定义,链...服务端2月18日 17:18
C语言 restrict 关键字有什么用?编译器如何利用它做优化?restrict 是 C99 引入的类型限定符,告诉编译器"这个指针是访问该内存区域的唯一途径",编译器据此可以做更激进的优化。
说白了,restrict 就是一份承诺:你向编译器保证通过这个指针访问的内存,不会通过其他指针再访问。编译器信了,就能省掉很多冗余的内存读取。
## 追问
### restrict 和普通指针有什么区别?
普通指针可能有"别名"(aliasing)——多个指针指向同一块内存:
```c
void add(int *a, int *b, int *c, int n) {
for (int i = 0; i < n; i++)
a...服务端2月18日 17:19
C语言 inline 关键字有什么用?和宏的区别及使用限制详解inline关键字向编译器建议将函数调用处展开为函数体,消除函数调用开销(压栈、跳转、返回),适合短小的频繁调用函数。inline与宏的区别在于:inline函数有类型检查,支持调试(可在调试器中单步进入),不会因括号问题产生意外行为,而宏只是文本替换,没有类型安全。但inline只是建议,编译器有权忽略——递归函数、包含循环或switch的复杂函数、虚函数通常不会被内联。函数体过长时编译器也会拒绝内联,因为代码膨胀反而降低指令缓存命中率。static inline结合了内部链接性和内联建议,适合放在头文件中,每个包含该头文件的翻译单元生成独立副本,不产生链接冲突。头文件中定义inlin...服务端2月18日 17:19
C语言结构体和C++ class 有什么区别?内存对齐/柔性数组详解在C语言中,结构体只能定义数据成员,不能包含成员函数,默认所有成员对外可见。C++中struct和class的唯一语法区别是默认访问权限:struct成员默认public,class成员默认private;默认继承权限也同理,struct默认public继承,class默认private继承。除此之外两者功能完全等价——C++的struct同样可以有构造函数、析构函数、虚函数、继承。内存对齐方面,编译器按成员声明顺序和各自对齐要求布局,通常按最大成员对齐,可用#pragma pack或alignas调整。位域允许在结构体中以位为单位指定成员宽度,节省空间但牺牲可移植性。柔性数组是结构体末...服务端2月18日 17:20
C语言预定义宏和条件编译怎么用?__FILE__/ifdef/## 详解C语言标准定义了一组预定义宏,在编译时由预处理器自动展开,主要用于调试和条件编译。常用宏包括:__FILE__展开为当前源文件名(字符串),__LINE__展开为当前行号(整数),__DATE__和__TIME__分别展开为编译日期和时间,__func__(C99)展开为当前函数名,__STDC__在符合标准的编译器下展开为1。条件编译通过#if、#ifdef、#ifndef、#elif、#else、#endif控制代码是否参与编译,核心指令是#ifdef和#ifndef,常用于头文件保护和平台适配。defined运算符可在#if表达式中检测宏是否定义,不关心其值。#pragma onc...服务端2月18日 17:26
C++ 指针和引用有什么区别?各自适用什么场景?指针是一个变量,存储另一个变量的内存地址,本身占用内存;引用是已存在变量的别名,与被引用对象共享同一内存地址。指针声明后可不初始化,也可以置为nullptr;引用必须在声明时绑定到一个对象,且不存在"空引用"。指针可以重新指向其他对象,引用一旦绑定就无法更改绑定目标——对引用赋值实际是修改所引用对象的值。指针支持算术运算(加减偏移、指针减法算距离),引用不支持任何算术操作。作为函数参数时,指针传递显式取地址,调用处能看出可能修改实参;引用传递语法上像值传递,但实际可修改实参,语义更隐蔽。返回值方面,返回指针要考虑空指针风险,返回引用要保证所引对象生命周期超出函数作用域,返回局部变量的引用...服务端2月18日 17:27
C++ 虚函数底层怎么实现?vtable/vptr 与动态绑定原理C++虚函数通过虚函数表(vtable)和虚指针(vptr)实现运行时多态。每个含有虚函数的类,编译器会为其生成一个vtable——一个静态数组,按声明顺序存放该类所有虚函数的函数指针。每个对象实例在内存布局的起始位置持有一个vptr,指向所属类的vtable。调用虚函数时,程序通过vptr找到vtable,再从表中取出对应槽位的函数指针进行间接调用,这就实现了动态绑定。单继承下对象只有一个vptr,多继承下会有多个vptr,分别指向不同基类的vtable。虚函数调用的开销主要是一次额外的间接寻址,现代CPU分支预测能大部分消除这个代价。纯虚函数在vtable中通常放入一个抛出异常的纯虚...