1. C 预处理器
①含义
C 预处理器是编译过程的第一个阶段,在源代码编译前处理以#
开头的指令。
②作用
- 文件包含(
#include
) - 宏定义(
#define
) - 条件编译(
#ifdef
,#ifndef
,#else
,#endif
) - 行控制(
#line
)和错误指示(#error
)
③用法
#include <stdio.h> // 包含标准输入输出库
#define PI 3.14159 // 定义宏
#ifdef DEBUG // 条件编译
#define DBG_MSG(x) printf(x)
#else
#define DBG_MSG(x)
#endif
④注意事项
- 宏定义不检查类型,可能导致意外行为
- 条件编译过多会降低代码可读性
- 避免使用嵌套复杂的宏
⑤例题
定义一个宏计算平方,并使用条件编译实现调试模式:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define SQUARE(x) ((x) * (x)) // 带括号的安全宏
#ifdef DEBUG
#define PRINT_DEBUG(x) printf("Debug: " x "\n")
#else
#define PRINT_DEBUG(x)
#endif
int main() {
PRINT_DEBUG("Starting program");
printf("Square of 5 is %d\n", SQUARE(5));//Square of 5 is 25
return 0;
}
2. _Noreturn
函数
①含义
_Noreturn
是 C11 标准引入的函数说明符,表示函数不会返回调用点(如终止程序或无限循环)。
②作用
- 帮助编译器优化代码
- 提高代码可读性,明确函数行为
③用法
_Noreturn void fatal_error(const char *msg) {
fprintf(stderr, "Error: %s\n", msg);
exit(EXIT_FAILURE);
}
_Noreturn void infinite_loop() {
while (1) { /* 无限循环 */ }
}
④注意事项
- 确保函数确实不会返回,否则导致未定义行为
- 不应用于可能返回的函数
⑤例题
实现一个错误处理函数,终止程序并打印错误信息:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
_Noreturn void handle_error(const char* msg) {
fprintf(stderr, "Fatal: %s\n", msg);
exit(EXIT_FAILURE);
}
int main() {
FILE* fp = fopen("nonexistent.txt", "r");
if (fp == NULL) {
handle_error("File not found");
}
// 后续代码不会执行,因为handle_error不会返回
return 0;
}
3. 数学库中的三角问题与类型变体
①含义
C 标准库提供三角函数(如sin
, cos
, tan
),参数为弧度制。tgmath.h
提供泛型数学函数,自动匹配参数类型。
②作用
- 处理三角函数计算
- 支持不同数据类型(
float
,double
,long double
)
③用法
#include <math.h> // 标准数学库
#include <tgmath.h> // 泛型数学库
double angle = 45.0;
double rad = angle * M_PI / 180.0; // 角度转弧度
double sin_val = sin(rad); // 计算正弦值
float x = 1.5f;
float y = tgsin(x); // 泛型函数,自动匹配float类型
④注意事项
- 三角函数参数需为弧度制
- 结果可能存在精度误差
tgmath.h
依赖编译器支持
⑤例题
计算并打印不同角度的正弦值:
#include <stdio.h>
#include <math.h>
int main() {
for (int degrees = 0; degrees <= 180; degrees += 30) {
double radians = degrees * M_PI / 180.0;
printf("sin(%d°) = %.4f\n", degrees, sin(radians));
}
return 0;
}
4. 通用工具库中的exit()
、atexit()
和qsort()
exit()
- 含义:终止整个程序,执行清理工作(如刷新缓冲区)。
- 作用:异常或正常终止程序。
- 用法:
#include <stdlib.h>
int main() {
if (error_condition) {
exit(EXIT_FAILURE); // 非零值表示异常退出
}
exit(EXIT_SUCCESS); // 等同于return 0;
}
atexit()
- 含义:注册程序终止时执行的函数。
- 作用:清理资源(如关闭文件、释放内存)。
- 用法:
#include <stdlib.h>
void cleanup() {
printf("Performing cleanup...\n");
}
int main() {
atexit(cleanup); // 注册清理函数
// 程序代码
return 0; // 退出前会调用cleanup()
}
qsort()
- 含义:快速排序算法,对数组进行排序。
- 作用:高效排序任意类型的数组。
- 用法:
#include <stdlib.h>
// 比较函数:升序排列整数
int compare_ints(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int main() {
int arr[] = {5, 3, 8, 1};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare_ints);
// arr 现在是 {1, 3, 5, 8}
return 0;
}
5. 断言库中的assert()
和_Static_assert
assert()
- 含义:运行时断言,验证程序假设。
- 作用:调试时检测逻辑错误。
- 用法:
#include <assert.h>
int divide(int a, int b) {
assert(b != 0); // 确保除数不为零
return a / b;
}
_Static_assert
- 含义:编译时断言,验证编译期常量表达式。
- 作用:确保代码符合特定条件(如结构体大小、枚举值范围)。
- 用法:
#include <assert.h>
struct Point {
int x;
int y;
};
_Static_assert(sizeof(struct Point) == 8, "Point struct size mismatch");
6. string.h
中的 memcpy()
和 memmove()
memcpy()
- 含义:内存块复制,不处理重叠内存。
- 作用:高效复制任意类型数据。
- 用法:
#include <string.h>
int src[5] = {1, 2, 3, 4, 5};
int dst[5];
memcpy(dst, src, sizeof(src)); // 复制src到dst
memmove()
- 含义:内存块复制,处理重叠内存。
- 作用:安全复制可能重叠的内存区域。
- 用法:
#include <string.h>
char str[] = "abcdef";
memmove(str + 2, str, 4); // 安全移动,结果:"ababcd"
7. 可变参数 stdarg.h
- 含义:处理可变数量的函数参数。
- 作用:实现类似
printf
的函数。 - 用法:
#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {
va_list args;
va_start(args, count); // 初始化参数列表
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int); // 获取下一个参数
}
va_end(args); // 清理参数列表
return total;
}
int main() {
printf("Sum: %d\n", sum(3, 10, 20, 30)); // 输出60
return 0;
}
注意事项:
- 必须指定固定参数以确定可变参数的起始位置
- 使用
va_start
初始化,va_end
清理 - 需自行处理参数类型和数量的验证