C语言关键字
目录
基本数据类型关键字
关键字 | 说明 | 示例 |
---|---|---|
void | 表示无类型,用于函数返回值或参数 | void func(void); |
char | 字符类型,通常占1字节 | char c = 'A'; |
int | 整型,通常为4字节 | int i = 10; |
float | 单精度浮点型,4字节 | float f = 3.14f; |
double | 双精度浮点型,8字节 | double d = 3.14159; |
类型修饰关键字
关键字 | 说明 | 示例 |
---|---|---|
short | 短整型,通常为2字节 | short s = 100; |
long | 长整型,至少4字节 | long l = 1000000L; |
signed | 有符号类型(默认) | signed int i = -10; |
unsigned | 无符号类型,不能表示负数 | unsigned int u = 10U; |
const | 声明常量,值不可更改 | const int MAX = 100; |
volatile | 告知编译器该变量可能被异步修改 | volatile int flag; |
存储类关键字
关键字 | 说明 | 示例 |
---|---|---|
auto | 自动存储(局部变量默认) | auto int var = 10; |
register | 建议将变量存放在寄存器中 | register int counter; |
static | 使局部变量保持其值;限制全局变量/函数作用域 | static int count = 0; |
extern | 声明一个在其他文件定义的变量 | extern int global_var; |
控制流关键字
关键字 | 说明 | 示例 |
---|---|---|
if | 条件语句 | if (x > 0) { /* 代码块 */ } |
else | 与if配合使用,表示否则 | if (x > 0) { /* 代码块 */ } else { /* 代码块 */ } |
switch | 多重分支语句 | switch (option) { case 1: /* 代码 */ break; } |
case | 用于switch语句中的分支标签 | case 1: printf("Option 1"); break; |
default | switch语句的默认分支 | default: printf("Invalid option"); |
for | 循环语句 | for (i=0; i<10; i++) { /* 代码块 */ } |
while | 当条件为真时循环执行 | while (condition) { /* 代码块 */ } |
do | 先执行后判断的循环 | do { /* 代码块 */ } while (condition); |
break | 跳出当前循环或switch语句 | break; |
continue | 跳过当前循环的剩余部分 | continue; |
goto | 无条件跳转到标签处(不推荐使用) | goto label; /* ... */ label: /* 代码 */ |
return | 从函数返回 | return value; 或 return; |
结构化类型关键字
关键字 | 说明 | 示例 |
---|---|---|
struct | 定义结构体类型 | struct Person { char name[50]; int age; }; |
union | 定义共用体类型,成员共享内存 | union Data { int i; float f; char str[20]; }; |
enum | 定义枚举类型 | enum Color { RED, GREEN, BLUE }; |
typedef | 为现有类型创建别名 | typedef unsigned int uint; |
其他关键字
关键字 | 说明 | 示例 |
---|---|---|
sizeof | 返回类型或表达式的字节大小 | size_t size = sizeof(int); |
C99/C11新增关键字
关键字 | 说明 | 示例 |
---|---|---|
inline | 建议编译器内联展开函数 | inline int max(int a, int b) { return a > b ? a : b; } |
restrict | 指示指针是访问该对象的唯一方式 | void copy(int* restrict dst, int* restrict src, int n); |
_Bool | 布尔类型(C99) | _Bool flag = 1; |
_Complex | 复数类型(C99) | _Complex double c = 1.0 + 2.0 * I; |
_Imaginary | 虚数类型(C99) | _Imaginary double im = 2.0 * I; |
_Atomic | 原子类型(C11) | _Atomic int shared_counter; |
_Thread_local | 线程局部存储(C11) | _Thread_local int thread_id; |
_Static_assert | 编译时断言(C11) | _Static_assert(sizeof(int) == 4, "Int must be 4 bytes"); |
_Noreturn | 表明函数不会返回(C11) | _Noreturn void exit_program(void); |
_Generic | 类型泛型表达式(C11) | _Generic(x, int: "int", float: "float", default: "other") |
关键字的使用示例
数据类型示例
int main() {
// 基本数据类型
char c = 'A'; // 字符
int i = 42; // 整数
float f = 3.14f; // 单精度浮点数
double d = 2.71828; // 双精度浮点数
// 类型修饰符
unsigned int ui = 100; // 无符号整数
long int li = 1000000L; // 长整数
const float pi = 3.14f; // 常量(不可修改)
return 0;
}
控制流示例
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
void print_day(int day) {
switch (day) {
case 1:
printf("Monday");
break;
case 2:
printf("Tuesday");
break;
// ...其他情况...
default:
printf("Invalid day");
}
}
void count_to_ten() {
for (int i = 1; i <= 10; i++) {
printf("%d ", i);
}
int j = 1;
while (j <= 10) {
printf("%d ", j);
j++;
}
int k = 1;
do {
printf("%d ", k);
k++;
} while (k <= 10);
}
存储类示例
// 文件作用域的静态变量(仅在当前文件可见)
static int counter = 0;
void increment() {
// 函数作用域的静态变量(保持值)
static int calls = 0;
calls++;
counter++;
printf("Function called %d times, counter = %d\n", calls, counter);
}
// extern关键字用于声明外部变量
extern int global_variable;
结构体和共用体示例
// 定义结构体
struct Person {
char name[50];
int age;
float height;
};
// 使用typedef创建类型别名
typedef struct {
int x;
int y;
} Point;
// 定义共用体(所有成员共享同一块内存)
union Data {
int i; // 4字节
float f; // 4字节
char str[8]; // 8字节
}; // 整个共用体大小为8字节(最大成员的大小)
// 定义枚举
enum Color {
RED, // 0
GREEN, // 1
BLUE // 2
};
关键字深入解析
const 关键字详解
const
是一个类型限定符,用于声明"只读"变量或参数,表示其值在初始化后不应被修改。
用途和特性:
-
创建只读变量:防止变量被意外修改
const int MAX_USERS = 100; // 声明常量 MAX_USERS = 200; // 编译错误:不能修改const变量
-
只读函数参数:表明函数不会修改传入的参数
void print_array(const int arr[], int size) { // 函数内不能修改arr指向的内容 // arr[0] = 100; // 编译错误 }
-
只读指针与指针常量:
// 指向常量的指针(不能通过此指针修改目标值) const int *ptr1 = &value; // *ptr1 = 100; // 编译错误 ptr1 = &other_value; // 可以更改指针指向 // 常量指针(指针本身不能更改指向) int * const ptr2 = &value; *ptr2 = 100; // 允许 // ptr2 = &other_value; // 编译错误 // 指向常量的常量指针(两方面都不能修改) const int * const ptr3 = &value;
-
与类型定义结合:
const struct Point origin = {0, 0}; // 常量结构体
最佳实践:
- 对不应修改的变量使用const可增强代码健壮性
- 函数参数中使用const可明确表达设计意图
- 结合指针使用时注意const位置的不同含义
volatile 关键字详解
volatile
告知编译器变量可能在程序控制外被改变,防止编译器优化掉对该变量的操作。
用途和特性:
-
硬件寄存器访问:
volatile uint32_t *gpio_port = (uint32_t*)0x40020000; // 指向外设寄存器 *gpio_port = 0x01; // 这个写入不会被优化掉
-
多线程共享变量:
volatile int shared_flag = 0; // 线程1 while (!shared_flag) { // 等待另一线程修改标志 // 没有volatile,编译器可能优化为无限循环 }
-
信号处理程序中的变量:
volatile sig_atomic_t signal_received = 0; void signal_handler(int sig) { signal_received = 1; }
-
结合const使用:
// 不能被代码修改,但可能被外部因素改变的变量 volatile const int sensor_value = 0;
注意事项:
- volatile不保证原子性或内存顺序,不应替代同步机制
- 现代多线程程序应使用适当的同步原语而非仅依赖volatile
- 主要用于直接硬件交互和特殊内存映射区域
static 关键字详解
static
在不同上下文中有不同的含义,影响变量的生命周期和可见性。
1. 局部变量中的static:
- 使变量在函数调用之间保持其值
- 仅初始化一次(首次调用时)
- 存储在静态数据区而非栈上
void counter() {
static int count = 0; // 仅在第一次调用时初始化
count++;
printf("Called %d times\n", count);
}
int main() {
counter(); // 输出: Called 1 times
counter(); // 输出: Called 2 times
counter(); // 输出: Called 3 times
return 0;
}
2. 全局变量/函数中的static:
- 将作用域限制在当前文件内
- 防止其他文件访问该标识符
- 实现模块的封装和隐藏实现细节
// file1.c
static int counter = 0; // 仅在file1.c中可见
static void helper() { // 仅在file1.c中可访问
counter++;
}
void public_function() {
helper();
printf("Counter: %d\n", counter);
}
// file2.c
extern int counter; // 错误:无法访问file1.c中的静态变量
helper(); // 错误:无法访问file1.c中的静态函数
3. 类中的static(C++相关,C中无此用法)
最佳实践:
- 使用static局部变量替代全局变量,减少全局命名空间污染
- 使用static限制不需要导出的函数和变量,提高封装性
- 注意静态变量在多线程环境中可能需要同步机制
extern 关键字详解
extern
用于声明外部变量或函数,表示其定义在其他地方(通常是另一个源文件)。
用途和特性:
-
引用其他文件中的全局变量:
// file1.c int global_counter = 0; // 定义 // file2.c extern int global_counter; // 声明 void increment() { global_counter++; // 使用file1.c中定义的变量 }
-
引用外部函数(通常隐式extern):
// file1.c void helper_function() { // 实现 } // file2.c extern void helper_function(); // 声明 // 或直接:void helper_function(); // extern可省略
-
与const结合使用:
// file1.c extern const int MAX_USERS; // 常量声明 // file2.c const int MAX_USERS = 100; // 常量定义
-
指定链接属性:
extern "C" { // 在C++中指定使用C链接约定 void c_function(); }
注意事项:
- extern只是声明而非定义,不分配存储空间
- 全局变量只应在一个文件中定义(初始化)
- 头文件中通常使用extern声明全局变量,在源文件中定义
- extern "C"是C++语法,用于避免C++名称修饰
inline 关键字详解
inline
向编译器提供将函数内联展开的建议,用于优化小而频繁调用的函数。
用途和特性:
-
减少函数调用开销:
inline int max(int a, int b) { return a > b ? a : b; } void process() { int result = max(5, 10); // 可能被编译为:int result = 5 > 10 ? 5 : 10; }
-
C99中的作用:
- 允许在多个翻译单元中定义同一个函数
- 提供外部链接的内联函数
-
内联函数vs宏:
// 宏定义 #define MAX(a, b) ((a) > (b) ? (a) : (b)) // 内联函数 inline int max(int a, int b) { return a > b ? a : b; }
注意事项:
- inline仅为建议,编译器可能忽略
- 复杂函数即使标记为inline也可能不被内联
- 过度使用可能导致代码膨胀
- 现代编译器通常能自动决定内联,不必显式标记
- C99标准要求同时使用static或extern
#define 指令详解
#define
是预处理器指令而非关键字,用于定义宏。
用途和特性:
-
简单常量定义:
#define PI 3.14159 #define MAX_BUFFER_SIZE 1024 #define DEBUG_MODE
-
带参数的宏:
#define SQUARE(x) ((x) * (x)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define SAFE_FREE(p) do { free(p); p = NULL; } while(0)
-
条件编译:
#define DEBUG #ifdef DEBUG printf("Debug info: %d\n", value); #endif #if defined(WIN32) // Windows特定代码 #elif defined(__linux__) // Linux特定代码 #else // 其他平台代码 #endif
-
字符串化和连接:
#define STRINGIFY(x) #x // 转为字符串 #define CONCAT(a, b) a##b // 符号连接 char *str = STRINGIFY(hello); // "hello" int xy = 10; int value = CONCAT(x, y); // 等同于 int value = xy;
注意事项:
- 宏没有类型检查,潜在风险高于内联函数
- 复杂宏需要谨慎括号处理
- do-while(0)结构可创建复合语句宏
- 避免在宏中使用有副作用的表达式
- 宏名通常全大写以区分
struct 关键字详解
struct
用于定义复合数据类型,将多个不同类型的数据组合在一起。
用途和特性:
-
基本结构体定义和使用:
struct Person { char name[50]; int age; float height; }; struct Person person1 = {"John", 30, 1.75}; printf("Name: %s\n", person1.name); person1.age = 31; // 修改成员
-
结构体指针:
struct Person *ptr = &person1; printf("Age: %d\n", ptr->age); // 使用箭头操作符 ptr->height = 1.80; // 通过指针修改成员
-
嵌套结构体:
struct Address { char street[100]; char city[50]; int zip_code; }; struct Employee { struct Person person; // 嵌套结构体 struct Address address; int employee_id; }; struct Employee emp; emp.person.age = 25; strcpy(emp.address.city, "New York");
-
结构体数组:
struct Person team[10]; team[0].age = 28; strcpy(team[1].name, "Alice");
-
自引用结构体(链表等):
struct Node { int data; struct Node *next; // 自引用 };
-
位域:
struct Flags { unsigned int ready:1; // 1位 unsigned int active:1; // 1位 unsigned int status:3; // 3位 }; // 仅占用1字节,而不是3个int
最佳实践:
- 使用typedef简化结构体使用
- 大结构体传参时使用指针避免拷贝开销
- 考虑内存对齐对结构体大小的影响
- 定义初始化和清理函数处理复杂结构体
union 关键字详解
union
定义一种特殊数据类型,多个成员共享同一内存空间,大小由最大成员决定。
用途和特性:
-
基本定义和使用:
union Data { int i; // 4字节 float f; // 4字节 char str[8]; // 8字节 }; // 总大小为8字节 union Data data; data.i = 123; printf("Integer: %d\n", data.i); data.f = 3.14; // 覆盖了整数值 printf("Float: %f\n", data.f);
-
内存节约:
// 不使用union:可能需要24字节 struct Value1 { int type; int int_val; float float_val; char *str_val; }; // 使用union:仅需12字节 struct Value2 { int type; union { int int_val; float float_val; char *str_val; } data; };
-
位操作和类型转换:
union FloatInt { float f; uint32_t i; }; union FloatInt val; val.f = 3.14; printf("Bit representation: 0x%08X\n", val.i);
-
网络字节序转换:
union { uint32_t value; uint8_t bytes[4]; } converter; converter.value = 0x12345678; printf("Byte0: 0x%02X\n", converter.bytes[0]); // 查看字节序
注意事项:
- 在同一时刻只有一个成员是"活动的"
- 使用非活动成员读取值是未定义行为
- 使用类型标记跟踪当前活动成员
- 不同编译器可能有不同的内存对齐规则
enum 关键字详解
enum
用于定义枚举类型,创建一组命名的整型常量。
用途和特性:
-
基本定义和使用:
enum Day { MONDAY, // 0 TUESDAY, // 1 WEDNESDAY, // 2 THURSDAY, // 3 FRIDAY, // 4 SATURDAY, // 5 SUNDAY // 6 }; enum Day today = WEDNESDAY; if (today == WEDNESDAY) { printf("It's Wednesday!\n"); }
-
指定值:
enum Status { ERROR = -1, SUCCESS = 0, PENDING = 100, RUNNING, // 101 FINISHED // 102 };
-
作为switch的选择器:
enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE }; int calculate(int a, int b, enum Operation op) { switch (op) { case ADD: return a + b; case SUBTRACT: return a - b; case MULTIPLY: return a * b; case DIVIDE: return b != 0 ? a / b : 0; default: return 0; } }
-
位标志:
enum FilePermission { READ = 1 << 0, // 0001 WRITE = 1 << 1, // 0010 EXECUTE = 1 << 2 // 0100 }; int permissions = READ | WRITE; // 0011 if (permissions & EXECUTE) { printf("Has execute permission\n"); }
最佳实践:
- 使用enum替代魔数常量提高可读性
- 枚举类型本质上是整型,不提供类型安全
- 考虑位掩码应用场景
- C中enum大小由实现决定,通常为int大小
_asm 关键字详解(编译器扩展)
_asm
或 asm
是编译器扩展,允许在C代码中嵌入汇编指令。不同编译器语法可能不同。
用途和特性:
-
Microsoft Visual C++语法:
void delay_loop() { _asm { mov ecx, 1000000 ; 循环计数 loop_start: nop ; 无操作 dec ecx ; 计数器减1 jnz loop_start ; 不为零则循环 } }
-
GCC语法:
void critical_section() { asm volatile ( "cli\n\t" /* 禁止中断 */ "mov eax, [data]\n\t" "add eax, 10\n\t" "mov [data], eax\n\t" "sti" /* 允许中断 */ : /* 输出操作数 */ : /* 输入操作数 */ : "eax", "memory" /* 被修改的寄存器 */ ); }
-
读取CPU特殊寄存器:
unsigned long read_cr0() { unsigned long cr0; asm volatile ("mov %%cr0, %0" : "=r" (cr0)); return cr0; }
-
优化关键性能代码:
// 使用SSE指令优化浮点运算 void vector_add(float *a, float *b, float *result, int size) { asm volatile ( "movups (%0), %%xmm0\n\t" "movups (%1), %%xmm1\n\t" "addps %%xmm1, %%xmm0\n\t" "movups %%xmm0, (%2)" : : "r" (a), "r" (b), "r" (result) : "xmm0", "xmm1", "memory" ); }
注意事项:
- 内联汇编不可移植,绑定特定架构
- 现代编译器优化能力强,手写汇编可能不如编译器优化
- 适用于访问硬件寄存器、实现原子操作等
- 不同编译器语法差异大
- 需要深入了解目标处理器架构