C语言中的关键词是编程语言的基础,它们被用来定义数据类型、控制结构、存储类型以及其他重要的编程操作。C语言标准定义了32个关键词,这些关键词可以分为四个主要类别:数据类型关键词、控制语句关键词、存储类型关键词和其他关键词。
1.数据类型关键词
数据类型关键词用于声明变量或函数的类型。这些关键词包括:
char:声明字符型变量或函数。
double:声明双精度浮点型变量或函数。
float:声明单精度浮点型变量或函数。
int:声明整型变量或函数。
short:声明短整型变量或函数。
long:声明长整型变量或函数。
unsigned:声明无符号类型变量或函数。
signed:声明有符号类型变量或函数。
struct:声明结构体变量或函数。
union:声明共用体(联合)数据类型。
void:声明函数无返回值或无参数,声明无类型指针。
enum:声明枚举类型。
2.控制语句关键词
控制语句关键词用于控制程序的流程。这些关键词包括:
for、do、while:用于循环结构。
break:跳出当前循环。
continue:结束当前循环,开始下一轮循环。
if、else:用于条件语句。
goto:无条件跳转语句。
switch、case、default:用于多重分支结构。
return:用于函数返回。
3.存储类型关键词
存储类型关键词用于声明变量的存储类别。这些关键词包括:
auto:声明自动变量。
extern:声明变量是在其他文件中定义。
register:声明寄存器变量。
static:声明静态变量。
4.其他关键词
其他关键词用于声明只读变量、计算数据类型长度、给数据类型取别名以及防止编译器优化。这些关键词包括:
const:声明只读变量。
sizeof:计算数据类型长度(字节数)。
typedef:给数据类型取别名。
volatile:所修饰的对象不能被编译器优化。
5.关键词的用法
1.数据类型
首先数据类型关键词不必多说,在声明所需的数据类型时用于声明所需要的数据类型。具体使用方法如下
int a = 10;
声明一个整型数据a,赋值为10。
2.控制语句
C语言中的控制语句关键词用于控制程序的执行流程,包括条件判断、循环执行和跳转等。也就是我们通俗来讲的语法,所有控制语句关键词用法如下
1.if
用于根据条件表达式的真假来决定是否执行某一段代码。
if (condition) {
// 执行代码
}
当condition 为真时执行代码块中的内容,否则跳过。
2.else
配合if
语句使用,表示条件不成立时执行的代码。
if (condition) {
// 条件成立时执行
} else {
// 条件不成立时执行
}
当if
条件为假时,执行else
后面的代码。
3.else if
用于在多个条件判断中选择其中一个符合条件的分支。
if (condition1) {
// 执行代码1
} else if (condition2) {
// 执行代码2
} else {
// 执行代码3
}
在if
的条件为假时,继续判断后面的else if
条件,直到找到为真为止。
4.switch
用于根据不同的值选择执行不同的代码块。常用于多个条件判断时。
switch (expression) {
case value1:
// 执行代码1
break;
case value2:
// 执行代码2
break;
default:
// 执行默认代码
}
根据expression
的值与各个case
的值进行匹配,匹配成功时执行相应的代码。若没有匹配项,则执行default
后的代码。
5.for
用于创建一个循环,常用于已知次数的循环。
for (initialization; condition; increment) {
// 循环体
}
先执行初始化语句,然后判断条件是否为真,若为真则执行循环体,再执行增量或更新操作。重复此过程,直到条件为假。
6.while
用于创建一个循环,常用于条件未知的循环。
while (condition) {
// 循环体
}
先判断条件是否为真,若为真则执行循环体,然后重新判断条件,直到条件为假。
7.do
与while
配合使用,构成do-while
循环,至少执行一次循环体(与while的区别),然后再判断条件。
do {
// 循环体
} while (condition);
先执行一次循环体,然后判断条件,若条件为真则继续执行循环,直到条件为假。
8.break
用于跳出循环或switch
语句,结束当前的执行过程。
break;
立即结束最近的for
、while
、do-while
循环或switch
语句的执行。
9.continue
用于跳过当前循环中的剩余语句,直接进入下一次循环的判断条件。
continue;
跳过当前循环中的后续代码,开始下一次循环的判断。(通常可以省略循环内的if判断)
10.goto
用于无条件跳转到程序中指定的标签处。
goto label;
// 其他代码
label:
// 跳转到此处
从代码中任意位置跳转到指定的标签位置,通常不推荐过度使用。会造成代码易读性降低,也容易造成代码结构混乱,一般不使用
3.存储类型
在C语言中,auto
、extern
、register
和 static
都是存储类说明符(Storage Class Specifiers),它们用来描述变量的存储方式、生命周期、作用域等特性。
1.auto
auto
是 C 语言中的默认存储类,它用于声明局部变量。实际上,局部变量如果没有显式指定存储类,默认就是 auto
。在大多数情况下,auto
关键字是可以省略的,因为它不会对变量的行为产生实质性的影响。
特点:
- 局部性:
auto
变量只在其所在的函数或代码块中有效。 - 自动存储:当函数调用结束时,
auto
变量会被销毁。它的生命周期是与函数调用的开始和结束相关联的。 - 作用域:
auto
变量的作用域仅限于声明它的代码块。
void foo() {
auto int x = 10; // 自动变量
printf("%d", x); // x 只能在 foo() 函数内使用
}
在现代 C 语言编程中,auto
关键字已不常用,因为我们声明的局部变量默认就是auto。
2.extern
extern
用于声明一个变量或者函数是在其他源文件中定义的。通过 extern
关键字,C语言程序可以引用其他文件中定义的变量或函数,而不需要在当前文件中重新定义它们。
特点:
- 链接外部符号:
extern
表示该变量或函数在其他文件中定义,告诉编译器该符号已经在其他地方声明过。 - 全局作用域:
extern
变量通常是全局变量,它的生命周期贯穿整个程序。 - 无内存分配:
extern
声明仅仅是声明,不会分配内存。内存分配在实际定义时发生。
// file1.c
int x = 10; // 在 file1.c 中定义变量 x
// file2.c
extern int x; // 在 file2.c 中声明变量 x
void foo() {
printf("%d", x); // 访问 file1.c 中定义的 x
}
这里,x
在 file1.c
中定义,在 file2.c
中声明并使用。
3.register
register
用来声明寄存器变量。它告诉编译器该变量应该尽可能保存在 CPU 的寄存器中,而不是内存中。这通常用于频繁访问的变量,以提高性能。虽然现代编译器通常能够自动优化变量的存储位置,但仍然可以使用 register
来建议编译器将某个变量存放在寄存器中。
特点:
- 存储在寄存器中:编译器会尽量把变量存储在 CPU 寄存器中,以加速对该变量的访问。
- 局部性:
register
变量只能是局部变量,不能是全局变量。 - 无法取地址:由于
register
变量存储在寄存器中,所以不能通过取地址符&
获取其地址。
void foo() {
register int count = 0; // 尝试将 count 存储在寄存器中
for (int i = 0; i < 100; i++) {
count++;
}
// printf("%p", &count); // 错误,无法获取寄存器变量的地址
}
这里,count
可能会被存储在寄存器中,以提高访问速度,但取决于编译器的优化策略。(本人很少使用)
4.static
static
用于声明静态变量,静态变量有两种主要用途:
- 静态局部变量:在函数内部声明时,
static
使得变量的值在函数调用结束后不会丢失,而是保留在内存中,直到程序结束。 - 静态全局变量:在文件作用域内声明时,
static
使得该变量只能在声明它的文件中访问,防止外部文件访问。
特点:
- 静态局部变量:静态局部变量的生命周期与程序相同,它在程序运行期间一直存在,即使函数调用结束,它的值仍然被保留。
- 静态全局变量:静态全局变量只在定义它的文件中可见,不能在其他文件中使用。
例子:
静态局部变量:
void foo() {
static int count = 0; // 静态局部变量
count++;
printf("%d\n", count); // 每次调用 foo(),count 都会累加
}
每次调用 foo
时,count
的值不会被重置,而是上次调用时的值。
静态全局变量:
static int globalCount = 0; // 静态全局变量,仅在当前文件内可见
void increment() {
globalCount++;
}
void printCount() {
printf("%d", globalCount);
}
globalCount
变量仅在当前文件中可见,其他文件无法访问。
这里有一个很有意思的区别,那静态局部变量和全局变量有什么区别呢??
个人认为有两大区别
1作用域
静态局部变量的作用域仅限于它所在的函数或代码块。也就是说,它只能在定义它的函数内访问,外部代码无法访问它。全局变量的作用域是整个文件(如果使用 static
修饰则局限于文件内部),并且可以在该文件的任何地方访问。
void foo() {
static int x = 10; // 仅在 foo 函数内部有效
printf("%d\n", x);
}
// 无法从外部访问 x
int x = 10; // 全局变量
void foo() {
printf("%d\n", x); // 在 foo 函数内访问全局变量
}
2 访问权限
静态局部变量只能在定义它的函数内访问,外部无法访问或修改它,即它的作用域受限于该函数。全局变量在整个程序中都可以访问,包括其他文件(通过 extern
声明)。
void foo() {
static int x = 5; // 静态局部变量
printf("%d\n", x);
}
int main() {
foo(); // 可以访问静态局部变量
// printf("%d", x); // 错误:x 不能在 main() 中访问
return 0;
}
int x = 10; // 全局变量
void foo() {
printf("%d\n", x); // 可以访问全局变量
}
int main() {
foo(); // 访问全局变量
printf("%d\n", x); // 也可以在 main 中访问
return 0;
}
4.其他关键字
1.const
const
关键字用于声明常量或只读变量。它保证了变量的值在初始化后无法被修改。在声明时,使用 const
可以确保某个值在程序执行过程中保持不变。
const
可用于常量或只读参数的定义,使得该变量在程序执行过程中不允许被改变。- 常用于函数参数,以保证输入数据不被修改。
- 还可以用于数组、指针、结构体等。(主要用途)
const int* ptr; // 声明一个指向常量的指针,指针所指向的数据不能修改
2.sizeof
sizeof
运算符用于返回类型或变量所占的内存字节数。它在编译时就会计算出结果,而不是在运行时计算。它是一个非常重要的工具,尤其是在处理动态内存分配、数组或不同类型时。
- 计算数据类型的大小。
- 计算数组的元素个数。
- 获取结构体或类对象的内存大小。
int x = 5;
printf("%lu\n", sizeof(x)); // 输出 int 类型所占字节数
通常被认为是string.h内的函数,也可以当作函数来调用。
3.typedef
typedef
用于为现有的数据类型创建一个新的别名。它不会创建新的数据类型,而是简单地为已有类型提供一个新的名称。这使得代码更易于阅读、理解和维护。
- 改进代码的可读性:尤其在结构体、指针、函数指针等复杂数据类型上,使用
typedef
可以让代码看起来更简洁。 - 创建结构体类型的别名,简化代码。
typedef struct {
int x;
int y;
} Point; // 创建一个结构体类型别名 Point
Point p1; // 使用 Point 来定义结构体变量
4. volatile
volatile
关键字用于告诉编译器,修饰的变量可能会在程序的不同地方被修改,而编译器在优化时不应假设该变量的值不会改变。它常用于硬件寄存器、外部设备的状态寄存器、或多线程程序中的共享数据。
volatile
关键字告诉编译器,该变量的值在任何时刻都可能被外部因素修改(例如硬件中断、外部输入或多个线程)。- 编译器不会对带有
volatile
修饰符的变量进行优化处理,避免将其缓存到寄存器中或减少对该变量的访问次数。
volatile int flag = 0;
void check_flag() {
while (flag == 0) { // 如果没有 volatile,编译器可能优化掉这个循环
// 等待 flag 变为非零
}
}
在多线程环境下,一个线程可能会修改 flag
,另一个线程需要读取这个值。如果没有 volatile
,编译器可能会假设 flag
不会发生变化,从而优化掉对它的检查。这会导致程序错误。