C PRIMER PLUS——第12节:C预处理器与C库

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 标准库提供三角函数(如sincostan),参数为弧度制。tgmath.h提供泛型数学函数,自动匹配参数类型。

②作用

  • 处理三角函数计算
  • 支持不同数据类型(floatdoublelong 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()

  1. 含义终止整个程序,执行清理工作(如刷新缓冲区)。
  2. 作用:异常或正常终止程序。
  3. 用法
#include <stdlib.h>

int main() {
    if (error_condition) {
        exit(EXIT_FAILURE);  // 非零值表示异常退出
    }
    exit(EXIT_SUCCESS);      // 等同于return 0;
}

atexit()

  1. 含义注册程序终止时执行的函数
  2. 作用:清理资源(如关闭文件、释放内存)。
  3. 用法
#include <stdlib.h>

void cleanup() {
    printf("Performing cleanup...\n");
}

int main() {
    atexit(cleanup);  // 注册清理函数
    // 程序代码
    return 0;  // 退出前会调用cleanup()
}

qsort()

  1. 含义快速排序算法,对数组进行排序
  2. 作用:高效排序任意类型的数组。
  3. 用法
#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()

  1. 含义运行时断言,验证程序假设
  2. 作用:调试时检测逻辑错误。
  3. 用法
#include <assert.h>

int divide(int a, int b) {
    assert(b != 0);  // 确保除数不为零
    return a / b;
}

_Static_assert

  1. 含义编译时断言,验证编译期常量表达式。
  2. 作用:确保代码符合特定条件(如结构体大小、枚举值范围)。
  3. 用法
#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()

  1. 含义内存块复制,不处理重叠内存
  2. 作用:高效复制任意类型数据。
  3. 用法
#include <string.h>

int src[5] = {1, 2, 3, 4, 5};
int dst[5];
memcpy(dst, src, sizeof(src));  // 复制src到dst

memmove()

  1. 含义内存块复制,处理重叠内存
  2. 作用:安全复制可能重叠的内存区域。
  3. 用法
#include <string.h>

char str[] = "abcdef";
memmove(str + 2, str, 4);  // 安全移动,结果:"ababcd"

7. 可变参数 stdarg.h

  1. 含义处理可变数量的函数参数
  2. 作用:实现类似printf的函数。
  3. 用法
#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清理
  • 需自行处理参数类型和数量的验证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

航Hang*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值