typedef、共用体、枚举、存储类型、分文件编程详细内容

发布时间:2026/7/21 20:51:46
typedef、共用体、枚举、存储类型、分文件编程详细内容 一、类型重定义typedeftypedef是C语言中的关键字用于为已有的数据类型定义一个新的名称别名。这可以提高代码的可读性和可维护性。1.1 基本用法语法格式typedef 原类型名 类型新名字;示例typedef unsigned int size_t;这样unsigned int a;和size_t a;就是等价的声明。1.2 重定义结构体类型1先定义结构体类型再重定义#include stdio.h struct student { int id; float score; }; int main(int argc, char const *argv[]) { typedef struct student STU; // 为struct student定义别名STU STU st; // 等价于 struct student st; STU *p st; // 等价于 struct student *p st; return 0; }2定义结构体同时进行重定义#include stdio.h typedef struct student { int id; float score; } STU; // 直接定义结构体并创建别名 int main(int argc, char const *argv[]) { STU st; // 直接使用别名 STU *p st; return 0; }1.3 typedef 和结构体指针#include stdio.h typedef struct student { int id; float score; } STU, *STP; // STU是结构体别名STP是指向该结构体的指针类型别名 int main(int argc, char const *argv[]) { STU st; // 结构体变量 STP p st; // 指针变量等价于 STU *p st; p-id 1; p-score 99.9; return 0; }判断规则根据结构体定义前是否有typedef关键字来判断定义的是变量还是类型。二、共用体联合体共用体union是一种特殊的数据类型允许在相同的内存位置存储不同的数据类型。所有成员变量共用同一块内存空间。2.1 定义格式union 共用体名 { 成员列表; };2.2 定义共用体变量语法union 共用体名 变量名;访问成员变量使用.运算符示例#include stdio.h union value { int a; char b; }; int main(int argc, char const *argv[]) { union value val; val.a 10; printf(val.a %d\n, val.a); // 输出10 val.b a; printf(val.b %c\n, val.b); // 输出a printf(val.a %d\n, val.a); // 输出97因为共用内存a的值被覆盖 return 0; }2.3 共用体特性所有成员共用一块地址空间修改一个成员会影响其他成员的值内存中的实际数据以最后一次赋值为准共用体的大小 ≥ 最大成员的大小需要满足内存对齐要求应用示例测试大小端#include stdio.h union value { int a; char b; }; int main(int argc, char const *argv[]) { union value val; val.a 0x12345678; if (val.b 0x78) { printf(小端存储Little Endian\n); } else if (val.b 0x12) { printf(大端存储Big Endian\n); } return 0; }三、枚举enum枚举是用户自定义的数据类型用于声明一组命名的整数常量提高代码可读性。3.1 定义格式enum 枚举类型名 { 常量1, 常量2, // ... };3.2 示例#include stdio.h enum Weekday { MONDAY 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }; int main(int argc, char const *argv[]) { int day; printf(请输入星期几1-7); scanf(%d, day); switch (day) { case MONDAY: printf(今天是星期一\n); break; case TUESDAY: printf(今天是星期二\n); break; // ... 其他case default: printf(输入错误\n); break; } return 0; }注意事项如果没有显式赋值第一个枚举常量默认为0后续常量依次递增可以给每个元素单独赋值如果某个元素没有赋值则其值为上一个元素的值加1四、存储类型C语言中的存储类型决定了变量的存储位置、生命周期和作用域。4.1 auto自动类型默认的存储类型修饰局部变量通常省略不写。变量存储在栈区函数结束时自动释放。4.2 static静态类型可以修饰局部变量、全局变量和函数。存储位置静态区/全局区.data段存放已初始化的变量.bss段存放未初始化的变量初始化默认初始化为0只初始化一次生命周期修饰局部变量时延长其生命周期到程序结束作用域限制修饰局部变量限制在当前函数内使用修饰全局变量和函数限制在当前文件中使用示例#include stdio.h void fun() { static int a 0; // 只初始化一次 a; printf(a %d\n, a); } int main(int argc, char const *argv[]) { fun(); // 输出a 1 fun(); // 输出a 2 fun(); // 输出a 3 return 0; }4.3 extern外部引用类型extern用于声明在其他文件中定义的全局变量或函数使得在当前文件中可以使用这些外部定义的变量和函数。示例///////////////////////num.c/////////////////// #include stdio.h static int n 10; // static修饰后n不能被外部引用只能限制在本文件中使用 static void fun() { printf(hello\n); } /////////////////////main.c//////////////////// #include stdio.h extern int n; // 声明外部变量n extern void fun(); // 声明外部函数fun() int main(int argc, char const *argv[]) { printf(n %d\n, n); // 编译错误n在num.c中是static的无法外部引用 fun(); // 编译错误fun()在num.c中是static的无法外部引用 return 0; }编译与执行gcc num.c main.c ./a.out4.4 register寄存器类型register建议编译器将变量存储在CPU寄存器中以提高访问速度。特点不能对寄存器变量取地址操作因为寄存器没有内存地址由于寄存器数量有限编译器可能不会将所有register变量都放入寄存器中当寄存器不足时register变量会像auto变量一样存储在栈中示例#include stdio.h int main(int argc, char const *argv[]) { register int i; // 建议编译器将i存储在寄存器中 for (i 0; i 1000000; i) { // 频繁访问的循环变量适合使用register } // int *p i; // 错误不能对register变量取地址 return 0; }五、分文件编程分文件编程是C语言中组织大型项目的常用方法通过将代码分散到多个文件中提高代码的可维护性和可重用性。5.1 头文件.h文件头文件通常包含以下内容宏定义#define类型重定义typedef结构体、共用体、枚举的定义函数声明函数原型外部变量声明extern注意全局变量一般不会直接定义在头文件中以避免多重定义错误。5.2 源文件.c文件源文件包含以下内容函数的定义实现变量的定义包含main函数的文件main.c包含子函数的文件fun.c、utils.c等5.3 分文件编程示例头文件head.h////////////////////head.h///////////////////// #ifndef HEAD_H // 防止头文件被重复包含 #define HEAD_H #include stdio.h // 函数声明 int add(int a, int b); // 结构体定义 struct student { int id; float score; }; #endif // HEAD_H主文件main.c/////////////////main.c////////////////////// #include head.h // 使用双引号包含自定义头文件 int main(int argc, char const *argv[]) { int result add(3, 5); printf(3 5 %d\n, result); struct student stu; stu.id 1; stu.score 95.5; printf(学生ID%d成绩%.1f\n, stu.id, stu.score); return 0; }函数实现文件fun.c//////////////fun.c/////////////////// #include head.h // 函数定义 int add(int a, int b) { printf(计算 %d %d\n, a, b); return a b; }5.4 编译与执行编译命令gcc main.c fun.c -o program执行命令./program5.5#include引用方式区别和的区别引用方式查找顺序适用场景#include filename.h直接去系统目录编译器指定的头文件路径查找标准库头文件如stdio.h、stdlib.h#include filename.h1. 先在当前目录查找2. 如果找不到再去系统目录查找自定义头文件项目内的头文件5.6 分文件编程的优点模块化将相关功能组织在一起便于维护代码复用头文件可以被多个源文件包含编译效率修改单个文件时只需重新编译该文件团队协作不同开发者可以同时处理不同文件隐藏实现细节头文件只暴露接口保护实现细节