int、char、float 都属于基本类型(算术类型),是c语言中内存里真正存值的最小单位;enum和_bool本质是整数,unsigned是修饰符而非新类型,long long和long double仍是基本类型。

int、char、float 这些到底算哪一类?
它们都属于**基本类型**(也叫“算术类型”),是 C 语言里最底层、不可再分的数据单位。不是“基础语法”,而是内存里真正存值的最小契约:比如 char 就是 1 字节,int 通常是 4 字节(但不绝对),float 是 IEEE 754 单精度格式——编译器按这个规则去分配和解释内存。
常见误区是把 enum 或 _Bool 当成“额外类型”,其实它们本质还是整数:enum 成员默认从 0 开始编号,最终存储就是 int;_Bool(或 bool 配合 <stdbool.h></stdbool.h>)只占 1 字节,值非 0 即 1,底层仍是整型操作。
-
unsigned不是新类型,只是修饰符:它改变的是解释方式(最高位变数据位),不是类型分类 -
long long和long double是 C99/C11 加入的,但仍是基本类型,不是构造体 - 别硬记“所有平台 int 都是 4 字节”——用
sizeof(int)实测,尤其嵌入式或旧编译器可能为 2 字节
struct、union、array 为什么不能直接赋值?
因为它们属于**构造类型**,是用户用基本类型“搭出来”的复合结构,内存布局由你定义,编译器不提供默认的逐字节拷贝逻辑(C89 甚至禁止 struct 赋值,C99 才放开)。
典型错误现象:my_struct_t a = {1,2}; my_struct_t b = a; 在老编译器报错;union 赋值后读错成员导致值乱跳;数组名当左值被误写成 arr = another_arr;(实际是非法的,数组名是常量地址)。
立即学习“C语言免费学习笔记(深入)”;
- 结构体赋值可行(C99+),但本质是 memcpy —— 若含指针成员,只复制指针值,不复制所指内容(浅拷贝)
-
union写入一个成员后读另一个,结果取决于内存重叠和字节序,属未定义行为,别依赖 - 数组要复制必须用
memcpy()或循环,不能直接用=
void* 到底能不能直接解引用?
不能。这是**指针类型**里最容易栽跟头的地方:void* 是通用地址容器,但 C 标准禁止对它直接解引用或做指针运算,因为编译器不知道它指向什么类型、该读几个字节。
常见错误:写 *ptr(ptr 是 void*)导致编译失败;或想用 ptr + 1 跳过一个 int,结果只跳了 1 字节(void* 的 +1 是 +1 字节,不是 +sizeof(int))。
- 必须先强制转成具体类型指针:比如
(int*)ptr,再解引用或运算 - 函数参数用
void*(如qsort的base)是为了泛型,但内部回调函数仍需强转回原类型 - 返回
void*的函数(如malloc)在 C 中可隐式转为其他指针类型,但 C++ 不行——跨语言混编时注意
void 类型为什么不能定义变量?
因为 void 表示“无类型”,没有大小、没有布局、无法实例化。它唯一合法用途是函数返回值(void func())或指针基类型(void*)。
试图写 void x; 或 void arr[10]; 会直接编译失败,错误信息通常是 “invalid use of void expression” 或 “size of void is not known”。
-
void函数里写return 123;同样报错——不能带值返回 - 别把
void和空结构体struct {}混淆:后者在 C11 是合法的(大小为 0),可用于柔性数组成员前导 - 需要“占位但不占空间”的场景,优先考虑
char或uint8_t,而不是幻想void可以当占位符
类型系统不是语法装饰,它绑定着内存解释权。一旦越界操作(比如把 float* 当 int* 解引用),结果就取决于 IEEE 浮点编码和整数补码怎么咬合——这种“巧合”在换平台、换编译器、升标准时大概率崩掉。











