C语言专题——关键字详解
C语言专题——关键字详解
- 前言
- 为什么这篇文章值得你点赞收藏?
- 适合谁读?
- 互动时间
- 关键字汇总
- 数据类型关键字
- 基本数据类型
- 类型修饰符
- 流程控制关键字
- 条件语句
- 循环语句
- 跳转语句
- 其他关键字
- 关键字用法避坑指南
- for循环
- 基本用法和执行顺序
- 循环变量
- 注意事项
- sizeof关键字
- 基本用法
- 示例代码
- 关键特性
- 常见应用场景
- 注意事项
- switch语句
- 基本语法
- 关键特性
- 示例代码
- 基本用法(带break)
- fall-through行为(省略break)
- 使用enum类型
- 注意事项
- 与if-else的对比
- 常见应用场景
- break和continue的区别
- 语法与基本作用
- 循环中的行为差异
- 示例对比
- 常见应用场景
- 注意事项
- const int * p 和 int * const p区别
- 柔性数组
- void类型的指针
- 核心特性
- 常见用法
- 作为函数参数(泛型编程)
- 作为函数返回值
- 实现通用数据结构
- 指针转换规则
- 隐式转换
- 显式强制转换
- 使用限制
- 不能直接解引用
- 不能进行指针算术运算
- 类型安全问题
- 典型应用场景
- union关键字和大小端
- union关键字
- 大小端字节序(Endianness)
- 使用union检测大小端
- union与大小端的应用场景
- 一些重要的编程建议
前言
学C语言的宝子们看过来!这篇耗时3天整理的「C语言关键字全攻略」终于完工啦~从32个关键字的分类解析到实战避坑指南,手把手带你吃透C语言的核心语法,收藏这篇=拥有一本「C语言关键字字典」,从此编程再也不怕语法坑!
为什么这篇文章值得你点赞收藏?
-
32个关键字系统分类
把C语言32个关键字按数据类型、流程控制、存储类等维度拆解,每个关键字配示例代码,比教科书更易懂!比如static
修饰变量和函数的不同作用域,volatile
防止编译器优化的场景,一看就明白~ -
避坑指南直击痛点
专门整理了for循环越界
、sizeof误用
、switch分支陷阱
等高频错误,每个坑都带调试示例和解决方案。比如为什么void*
指针不能直接解引用?const int*
和int* const
到底怎么区分?这里全讲透! -
进阶知识一网打尽
除了基础关键字,还涵盖柔性数组、大小端检测、union
与内存对齐等进阶内容。用union
检测系统字节序的代码直接复制就能用,面试被问到时再也不慌~
适合谁读?
- 刚入门C语言,被关键字搞到头晕的新手
- 想系统梳理知识体系的编程学习者
- 需要查缺补漏的开发人员
互动时间
如果你在学C语言时遇到过关键字相关的奇葩bug,或者想让我讲解某个语法点,可以在评论区留言~觉得文章有用的话,别忘了「点赞+收藏+关注」,后续会更新更多C语言进阶干货哦!
关键字汇总
C语言共有32个关键字,用法分类整理如下:
数据类型关键字
基本数据类型
int
:声明整数类型变量,如int age = 25;
float
:声明单精度浮点型变量,如float price = 9.99;
double
:声明双精度浮点型变量,如double pi = 3.14159;
char
:声明字符型变量,如char grade = 'A';
void
:表示无类型,常用于函数返回值或指针,如void printHello();
类型修饰符
-
short
:修饰整数,缩短其长度,如short int num = 100;
-
long
:修饰整数或双精度浮点数,加长其长度,如long int distance = 1000000L;
-
signed
:声明有符号数,如signed int balance = -500;
-
unsigned
:声明无符号数,如unsigned int count = 1000;
-
const
:声明只读变量,如const float PI = 3.14;
-
volatile
:告诉编译器变量值可能意外改变,如volatile int sensorValue;
定义变量的时候加上这个关键字,可以防止编译器优化。另外程序在读取这个变量的时候,即便上一次的读取值在cashe中,也必须从内存中重新读取。 -
auto
:自动变量(默认),如auto int temp;
等效于int temp;
。在缺省情况下,编译器默认所有变量都是auto的,就当它不存在吧。 -
register
:建议编译器将变量存储在寄存器中,如register int counter;
当然“建议”也只是“建议”而已,在代码编译中不一定能放进寄存器里面,毕竟寄存器数量有限,而且还有其他用途。如果一个变量需要快速访问,可以定义为此类型。 -
static
- 修饰
变量
- 修饰全局变量,则作用域是从定义变量处开始,到文件结束处,其他文件无法使用此变量。即便在其他文件中extern此变量也无法使用,仅限本文件使用。
- 修饰局部变量,在函数体内部定义,如函数内部定义
static int count = 0;
它只能在函数体内使用,但延长了变量的生命周期,在退出函数之后此变量仍然存在。从生命周期上看,跟全局变量无异。
- 修饰
函数
- 函数前加static,就是静态函数,使得函数的作用域仅限在本文件,其他文件无法调用此函数。这样的好处是不用担心与其他文件中的函数重名。
- 修饰
-
extern
:声明外部变量,比如在一个源文件里面定义了变量int sharedVar;
,在另一个文件中需要使用此变量,就需要写extern int sharedVar;
才可以使用此变量。
流程控制关键字
条件语句
if
:条件判断,如if (score >= 60) { ... }
else
:与if
配合使用,如else { ...}
switch
:多分支选择,如switch (day) { case 1: ...}
case
:用于switch
语句中,标记每个分支default
:switch
语句中的默认分支
循环语句
for
:固定次数循环,如for (int i=0; i<10; i++) { ... }
while
:条件循环,如while (condition) { ... }
do
:与while
配合,至少执行一次,如do { ... } while (condition);
break
:跳出循环或switch
语句continue
:跳过本次循环剩余部分,继续下次循环
跳转语句
goto
:无条件跳转,如goto found;
return
:从函数返回值,如return result;
其他关键字
struct
:定义结构体类型,如struct Point { int x, y; };
union
:定义共用体类型,如union Data { int i; float f; };
enum
:定义枚举类型,如enum Color { RED, GREEN, BLUE };
typedef
:为类型定义别名,如typedef unsigned int uint32_t;
sizeof
:计算数据类型或变量大小,如sizeof(int)
关键字用法避坑指南
for循环
基本用法和执行顺序
在for循环中,容易忽略一点,就是执行顺序。
for(代码1; 代码2;代码3)
{
循环体;
}
程序执行到for循环
这里,首先执行代码1
,之后执行代码2
,之后执行循环体
,最后执行代码3
,之后又执行代码2
,执行循环体
,再执行代码3
,执行代码2
……
例如下面的例子:
int i = 0;for(printf("apple\n"); \printf("banana\n"); \printf("orange\n")){printf("Hello world\n");if(i == 1){break;} i ++; }
循环变量
在for循环之外定义的变量,可以在for循环里面定义同名变量用于控制循环次数。
int i = 50;
for(int i = 0; i < 5; i++)
{printf("In for circulation : i = %d\n", i);
}printf("out of for circulation : i = %d\n", i);
循环变量的作用域只在循环体有效。
for(int i = 0; i < 5; i++){ //循环体}i = 100; // 报错!没有定义此变量
注意事项
- 除非必要,避免在循环体中直接修改循环变量。
- 若需调整迭代逻辑,优先使用continue或break。
- 数组越界访问。循环索引超出数组边界,导致未定义行为(如段错误、数据损坏)。
示例代码:
int arr[5];
for (int i = 0; i <= 5; i++) { // 错误:i=5时越界arr[i] = i; // 访问arr[5]超出合法范围(0~4)
}
正确做法:始终确保索引范围为0到数组长度-1。
使用sizeof计算数组长度:
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
{// ...
}
sizeof关键字
sizeof是关键字,不是函数!
sizeof
是一个编译时一元运算符,其主要功能是计算数据类型或者变量在内存中所占的字节数。下面为你详细介绍它的用法、特点以及相关注意事项:
基本用法
sizeof
有两种使用形式:
- 计算数据类型的大小:
sizeof(类型名)
- 计算变量的大小:
sizeof(变量名)
或者sizeof 变量名
(后一种形式仅适用于变量)例如:
int i = 0;
int b = sizeof i;//b = 4
printf("b = %d\n", b);
示例代码
sizeof 运算符返回的类型是 size_t
。下面先讲一下%zu
格式说明符的作用:
%z
是长度修饰符,它表明要输出的数值类型是size_t
。u
代表无符号十进制整数。
所以,%zu
专门用于正确输出size_t
类型的值,不管该值在当前系统中是32位还是64位。
#include <stdio.h>int main() {// 计算基本数据类型的大小printf("char: %zu 字节\n", sizeof(char)); // 通常输出1printf("int: %zu 字节\n", sizeof(int)); // 通常输出4printf("float: %zu 字节\n", sizeof(float)); // 通常输出4printf("double: %zu 字节\n", sizeof(double)); // 通常输出8// 计算变量的大小int num = 100;printf("num: %zu 字节\n", sizeof num); // 可以省略括号printf("num: %zu 字节\n", sizeof(num)); // 与上一行等价// 计算数组的大小int arr[5];printf("arr: %zu 字节\n", sizeof(arr)); // 输出4*5,等于20printf("arr元素个数: %zu\n", sizeof(arr)/sizeof(arr[0])); // 输出5// 计算结构体的大小struct Point {int x;int y;};printf("struct Point: %zu 字节\n", sizeof(struct Point)); // 输出8(4+4)return 0;
}
关键特性
- 编译时求值:
sizeof
的计算过程是在编译阶段完成的,不会在程序运行时执行。因此,它可以用于定义数组大小,例如:int arr[sizeof(int)];
(不过这种写法并不常见)。
int arr0[sizeof(int) * 10] = {0};printf("sizeof(arr) = %zu\n",sizeof(arr0));//sizeof(arr) = 160
- 返回值类型:
sizeof
的返回值类型是size_t
,在打印时需要使用%zu
格式说明符。 - 对指针的处理:若
p
是指针,sizeof(p)
返回的是指针本身的大小(在32位系统中通常是4字节,在64位系统中通常是8字节),而非指针所指向对象的大小。例如:
int *p = malloc(100 * sizeof(int));
printf("%zu\n", sizeof(p)); // 输出4(32位系统)
printf("%zu\n", sizeof(*p)); // 输出4(int的大小)
- 对数组的处理:
sizeof
作用于数组名时,返回的是整个数组的大小,而非指针的大小。但若数组作为参数传递给函数,数组名会退化为指针。例如:
void func(int arr[]) {printf("%zu\n", sizeof(arr)); // 输出4(32位系统),数组退化为指针
}
/*上面的函数等效于:
void func(int *arr)
{printf("%zu\n", sizeof(arr));
}
*/int main() {int arr[10];printf("%zu\n", sizeof(arr)); // 输出40(4*10)func(arr);return 0;
}
- 结构体的内存对齐:结构体的大小可能会大于其各成员大小之和,这是因为编译器为了提高内存访问效率,会进行内存对齐操作。例如:
struct Example {char c; // 1字节int i; // 4字节short s; // 2字节
};
// 由于内存对齐,该结构体的大小通常为12字节,而非7字节
内存对齐的时候,以占用空间最大的成员变量为准,然后进行内存对齐操作。比如int类型占用空间最大,是4字节,所以就是4字节对齐。存放char只需要1字节,但后面是int,故空出3字节,再存放int类型,最后short类型原本2字节就可以,但要求4字节对齐,导致最后占用了12字节。
但是成员的顺序也会影响到内存对齐。比如:
struct Example {char c; // 1字节short s; // 2字节int i; // 4字节
};
// 由于内存对齐,该结构体的大小通常为8字节,而非7字节
将成员的顺序改变之后,占用的内存就变成了8字节。
常见应用场景
- 动态内存分配:在使用
malloc
、calloc
等函数分配内存时,sizeof
能确保分配的内存大小与数据类型相匹配。例如:
int *arr = malloc(10 * sizeof(int)); // 分配10个int的空间
- 计算数组元素个数:通过
sizeof(arr)/sizeof(arr[0])
可以计算出数组的元素个数。例如:
int arr[] = {1, 2, 3, 4, 5};
int count = sizeof(arr)/sizeof(arr[0]); // count的值为5
- 平台无关性编程:使用
sizeof
可以编写不依赖于特定平台数据类型大小的代码,增强代码的可移植性。
注意事项
- 不要对函数调用使用
sizeof
:sizeof
不会执行函数,它只关心函数返回值的类型。例如:
int func() { return 10; }
printf("%zu\n", sizeof(func())); // 输出4(int的大小),函数不会被调用
- 对
void
类型使用sizeof
:例如,sizeof(void)
得到的结果是1。
printf("sizeof(void): %zu 字节\n", sizeof(void)); //输出1
- 对不完整类型使用
sizeof
是非法的:例如,声明但未定义的结构体不能使用sizeof
。
typedef struct Point Point; // 前置声明int main() {printf("%zu\n", sizeof(Point)); // 错误!未定义Pointreturn 0;
}// 即使在后面定义了结构体,这里的错误也不会被修正
struct Point { int x, y; };
switch语句
在C语言中,switch
语句是一种多分支选择结构,用于基于某个表达式的值来执行不同的代码块。它提供了一种比嵌套if-else
语句更清晰、更高效的方式来处理多种可能的情况。
基本语法
switch (expression) {case constant1:// 当expression等于constant1时执行的代码break;case constant2:// 当expression等于constant2时执行的代码break;...case constantN:// 当expression等于constantN时执行的代码break;default:// 当expression不匹配任何case时执行的代码break;
}
关键特性
-
表达式类型限制:
expression
必须是整数类型(如int
、char
、enum
)或可以隐式转换为整数类型的表达式。- 不支持浮点数或字符串作为表达式类型。
-
case标签要求:
- 每个
case
标签后的值必须是常量表达式,如字面量或宏定义,不能是变量。 - 同一个
switch
中,所有case
标签的值必须唯一。
- 每个
-
break语句的作用:
- 当执行到
break
时,会跳出整个switch
语句。 - 如果省略
break
,程序会继续执行后续case
的代码(称为"fall-through"),直到遇到break
或switch
结束。
- 当执行到
-
default分支:
- 可选的
default
分支会在所有case
都不匹配时执行。 - 通常放在
switch
的末尾,但位置不影响功能。
- 可选的
示例代码
基本用法(带break)
#include <stdio.h>int main() {int day = 3;switch (day) {case 1:printf("Monday\n");break;case 2:printf("Tuesday\n");break;case 3:printf("Wednesday\n"); // 匹配此分支,执行后跳出break;case 4:printf("Thursday\n");break;default:printf("Other day\n");}return 0;
}
fall-through行为(省略break)
int main() {int month = 2;switch (month) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:printf("31 days\n"); // 1、3、5、7、8、10、12月共有此输出break;case 4:case 6:case 9:case 11:printf("30 days\n"); // 4、6、9、11月共有此输出break;case 2:printf("28 or 29 days\n"); // 2月特殊处理break;default:printf("Invalid month\n");}return 0;
}
使用enum类型
#include <stdio.h>enum Color { RED, GREEN, BLUE };int main() {enum Color c = GREEN;switch (c) {case RED:printf("Color is red\n");break;case GREEN:printf("Color is green\n"); // 匹配此分支break;case BLUE:printf("Color is blue\n");break;}return 0;
}
注意事项
-
case标签不能重复:
switch (x) {case 1: ...case 1: ... // 错误!重复的case值 }
-
避免空case块:
switch (x) {case 1: // 无代码,会fall-through到下一个casecase 2:printf("x is 1 or 2\n");break; }
-
表达式结果必须是整数类型:
float f = 1.5; switch (f) { // 错误!不支持浮点数case 1.5: ... // 错误!case值必须是整数常量 }
-
嵌套switch:
可以在一个switch
内部嵌套另一个switch
,但要注意标签作用域:switch (x) {case 1:switch (y) {case 1: ...case 2: ...}break;case 2: ... }
与if-else的对比
- switch优点:
- 代码更简洁,尤其在处理大量分支时。
- 编译器可能会优化为跳转表(jump table),执行效率更高。
- switch缺点:
- 只能基于整数表达式进行判断。
- 每个case必须是常量值。
常见应用场景
- 菜单选择系统。
- 根据错误码执行不同处理。
- 状态机实现。
break和continue的区别
在C语言中,break
和continue
是用于控制循环流程的两个关键字,它们的主要区别在于对循环执行的影响不同。下面从语法、作用和示例三个方面详细说明:
语法与基本作用
关键字 | 语法 | 作用范围 | 执行效果 |
---|---|---|---|
break | break; | 只能用于for 、while 、do-while 循环或switch 语句 | 对于循环语句,程序跳出循环。 对于switch 语句,程序跳出switch 语句。 |
continue | continue; | 只能用于for 、while 、do-while 循环 | 跳过当前循环体中剩余的代码,直接进入下一次循环的条件判断(for 循环还会执行更新表达式)。 |
循环中的行为差异
for (初始化; 条件; 更新) {if (条件A) break; // 终止整个循环,不再执行更新和条件判断if (条件B) continue; // 跳过剩余代码,执行更新 → 条件判断
}
示例对比
示例1:break
的效果
for (int i = 0; i < 5; i++) {if (i == 3) break; // 当i=3时终止循环printf("%d ", i);
}
// 输出:0 1 2
示例2:continue
的效果
for (int i = 0; i < 5; i++) {if (i == 3) continue; // 当i=3时跳过后续代码,进入下一次循环printf("%d ", i);
}
// 输出:0 1 2 4
常见应用场景
关键字 | 典型应用场景 |
---|---|
break | - 在switch 语句中跳出分支- 提前终止循环(如找到目标值后) - 避免无限循环 |
continue | - 过滤某些不需要处理的情况(如跳过无效数据) - 简化嵌套条件判断 |
注意事项
-
作用范围:
break
和continue
只能影响当前所在的最内层循环。若要跳出多层循环,需使用goto
。
-
在
do-while
中的差异:continue
在do-while
中会直接跳到条件判断,而do-while
的特点是至少执行一次循环体。
const int * p 和 int * const p区别
const int * p
:p可变,p指向的对象不可变。
int const * p
:p可变,p指向的对象不可变。
int * const p
:p指向的对象可变,p不可变。
const int * const p
:p和p指向的对象都不可变。
注意:记忆方法,将类型名int
去掉,拿第一个来说,去掉之后是:const * p
,const修饰的是*p
,也就是p
指向的对象,所以指向的对象不可变。
柔性数组
/*定义柔性数组*/
typedef struct st_type
{int i; // 4字节int a[];
}type_a;int main()
{printf("sizeof(type_a) = %zu\n", sizeof(type_a));type_a *p = (type_a *)malloc(sizeof(type_a) + 10 * sizeof(int));for(int i = 0; i < 10; i++){p->a[i] = i;}for(int i = 0; i < 10; i++){printf("p->a[%d] = %d\n", i, p->a[i]);}free(p);
}
执行结果:
注意:
- 使用了malloc之后,记得free。
- 访问数组的时候,下标不要越界,否则可能引发问题。关键是编译不报错,程序可以正常运行。比如:
void类型的指针
在C语言中,void*
(空指针)是一种特殊的指针类型,它可以指向任意类型的数据,但不包含关于所指对象类型的信息。以下是关于void*
的详细解析:
核心特性
- 通用指针:
void*
可以存储任何类型的指针,无需显式类型转换。 - 无类型信息:编译器不知道
void*
指向的数据类型,因此不能直接解引用或进行指针算术运算。 - 大小固定:在32位系统中通常为4字节,64位系统中为8字节。
常见用法
作为函数参数(泛型编程)
用于接收任意类型的指针,实现不依赖特定类型的函数。
示例:内存复制函数
void* memcpy(void* dest, const void* src, size_t n);
dest
和src
可以是任意类型的指针,函数内部通过逐字节复制实现通用操作。
作为函数返回值
返回指向未知类型的指针,常见于内存分配函数。
示例:动态内存分配
void* malloc(size_t size); // 返回指向新分配内存的void*
int* ptr = (int*)malloc(sizeof(int)); // 使用时需强制类型转换
实现通用数据结构
在链表、栈等数据结构中存储任意类型的数据。
示例:通用链表节点
struct Node {void* data; // 可存储任意类型的数据struct Node* next;
};
指针转换规则
隐式转换
- 其他指针 →
void*
:无需显式转换。int num = 42; void* p = # // 合法:int*自动转换为void*
void* → 其他指针
:在C语言中必须显式强制转换。int* q = (int*)p; // C语言中需写为 (int*)p
显式强制转换
使用void*
前必须转换为具体类型:
int num = 42;
void* p = #
int value = *(int*)p; // 先转换为int*,再解引用
使用限制
不能直接解引用
void* p = malloc(sizeof(int));
*(int*)p = 10; // 正确:先转换为int*
// *p = 10; // 错误:void*不能直接解引用
不能进行指针算术运算
void* p = arr;
p++; // 错误:void*不能进行算术运算
(int*)p + 1; // 正确:转换为具体类型后可运算
类型安全问题
若强制转换为错误类型,可能导致未定义行为:
double d = 3.14;
void* p = &d;
int x = *(int*)p; // 错误:将double*误转为int*
典型应用场景
场景 | 示例函数/操作 |
---|---|
内存管理函数 | malloc() 、calloc() 、realloc() 、free() 返回/接受 void* |
内存操作函数 | memcpy() 、memset() 、memcmp() 使用 void* 作为参数 |
回调函数 | 通过 void* 传递上下文数据(如 qsort() 的比较函数) |
通用数据结构 | 链表、哈希表等存储任意类型数据的节点使用 void* |
union关键字和大小端
union关键字
基本概念
- 共用体:所有成员共享同一块内存空间,其大小由最大成员决定。
- 特点:修改一个成员会影响其他成员的值。
示例代码
#include <stdio.h>union Data {int i; // 4字节char c[4]; // 4字节
};int main()
{union Data data;data.i = 0x12345678; // 假设int为4字节// 访问不同成员printf("data.i address : 0x%x, i: 0x%X\n", &(data.i), data.i); // 输出: 0x12345678printf("data.c[0] address : 0x%x, c[0]: 0x%X\n", &(data.c[0]), data.c[0]); // 输出取决于大小端printf("data.c[1] address : 0x%x, c[1]: 0x%X\n", &(data.c[1]), data.c[1]); // 输出取决于大小端printf("data.c[2] address : 0x%x, c[2]: 0x%X\n", &(data.c[2]), data.c[2]); // 输出取决于大小端printf("data.c[3] address : 0x%x, c[3]: 0x%X\n", &(data.c[3]), data.c[3]); return 0;
}
大小端字节序(Endianness)
定义
- 大端序(Big Endian):数据的高位字节存储在内存的低地址,低位字节存储在高地址。
例如:整数0x12345678
的存储顺序为12 34 56 78
。(从左到右,地址依次增大) - 小端序(Little Endian):数据的低位字节存储在内存的低地址,高位字节存储在高地址。
例如:整数0x12345678
的存储顺序为78 56 34 12
。(从左到右,地址依次增大)
使用union检测大小端
利用union成员共享内存的特性,可以编写一个函数检测系统的字节序:
#include <stdio.h>int isLittleEndian() {union {int i;char c;} u;u.i = 1; // 二进制: 0x00000001// 若c为1,说明低地址存储的是低位字节(小端序)return u.c == 1;
}int main() {if (isLittleEndian()) {printf("小端序系统\n");} else {printf("大端序系统\n");}return 0;
}
原理:
- 整数
1
的二进制表示为0x00000001
(假设32位)。 - 在小端序中,低地址存储
01
,高地址存储00 00 00
。 - 在大端序中,低地址存储
00
,高地址存储00 00 01
。 - 通过访问
char
成员(只占1字节),可以读取低地址的值来判断字节序。
union与大小端的应用场景
访问多字节数据的单个字节
- 通过union可以直接操作整数的各个字节:
union {uint16_t word;struct {uint8_t low; // 低字节uint8_t high; // 高字节} bytes; } u;u.word = 0x1234; printf("低字节: 0x%X\n", u.bytes.low); // 小端序输出0x34,大端序输出0x12 printf("高字节: 0x%X\n", u.bytes.high); // 小端序输出0x12,大端序输出0x34
一些重要的编程建议
- 所有只读变量、宏、枚举变量都使用全部大写字母命名。
- 定义变量的时候尽量初始化,尤其是指针要初始化为NULL。
- 布尔类型是C语言中没有定义的,需要我们自己定义。
typedef enum
{FALSE = 0,TRUE = 1
}bool;bool bTest = TRUE;
- 不要使用return返回函数的局部变量。
- void * 指针可以被任何类型的指针赋值,但不能直接拿void * 类型的指针进行运算。如果函数入参是这个类型,那么就意味着可以接受任何指针。
int i = 50;void * pv = NULL;int *pint = &i;pv = pint;printf("pv = %d\n", *(int *)pv);//使用的时候必须强制转换
enum
枚举类型的成员的值必须是int类型能表述的。与#define
的区别在于#define
是预处理的时候进行简单的替换,而枚举是编译的时候确定其值。枚举是一个集合,代表一类值。枚举更加安全,对于函数入参,可以判断它是不是枚举中的一个,更加成体系。
本文结束,如果对你有帮助,欢迎点赞、收藏、转发。关注!