0Pricing
C Academy · 课时

条件编译

ifdef 与宏

条件编译 是 CoddyKit 上的免费 C Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

预处理器

在编译器真正看到您的代码之前,预处理器会先运行。它会处理每个以 # 开头的行,包括包含指令、宏和条件指令。

条件编译允许您根据在这一阶段计算出的条件,包含或排除代码块,从而用一份源代码生成不同的构建结果。

定义宏

#define 用于创建宏。不指定值时,它只是一个稍后可以测试的标志。

类对象宏会将名称替换为文本;标志则只表示某项已被设置。

#define MAX_USERS 100   /* value macro */
#define DEBUG          /* flag macro */

ifdef 和 ifndef

#ifdef NAME 仅在 NAME 已定义时保留代码块。#ifndef 仅在 NAME 未定义时保留代码块。

这里的调试打印只存在于调试构建中。如果未定义 DEBUG,编译器甚至根本看不到这一行。

#include <stdio.h>
#define DEBUG

int main(void) {
#ifdef DEBUG
    printf("debug: starting\n");
#endif
    printf("running\n");
    return 0;
}

if、elif 和 else

#if 会计算一个常量整数表达式。结合 #elif 和 #else,即可实现多路选择。

这段代码会根据版本号宏选择相应代码。

#include <stdio.h>
#define VERSION 2

int main(void) {
#if VERSION >= 2
    printf("new feature on\n");
#else
    printf("legacy mode\n");
#endif
    return 0;
}

defined 运算符

在 #if 内,您可以使用 defined(NAME) 测试某个名称是否已定义,并使用 && 和 || 组合多个测试。

这种方式比 #ifdef 更灵活,因为后者只能测试一个名称。

#if defined(LINUX) && !defined(EMBEDDED)
    /* desktop Linux code */
#endif

在编译时定义

您不必将宏硬编码在代码中。-D 标志可以在命令行上定义宏。

构建系统正是通过这种方式切换功能,而无需编辑源代码。-DDEBUG 等同于在每个文件顶部写入 #define DEBUG。

gcc -DDEBUG -DVERSION=3 -o app app.c

平台检测

编译器会预先定义描述目标平台的宏。您可以利用这些宏编写可移植代码。

  • _WIN32 — Windows(32 位或 64 位)
  • __linux__ — Linux
  • __APPLE__ — macOS / iOS

请根据这些宏进行分支,以调用正确的平台 API。

#ifdef _WIN32
    #include <windows.h>
#else
    #include <unistd.h>
#endif

头文件包含保护

条件指令的经典用途是包含保护,它可以阻止头文件被处理两次。

第一次包含时会定义保护宏;后续包含会跳过主体,因为该宏已经定义。

#ifndef UTILS_H
#define UTILS_H

int add(int a, int b);

#endif /* UTILS_H */

注释掉代码

#if 0 ... #endif 可以可靠地禁用一个代码块,即使该代码块本身已经包含注释。

与 /* */ 不同,它可以安全嵌套,因此是在调试期间临时排除代码的标准方式。

#if 0
    legacy_function();   /* disabled for now */
    /* with internal comments too */
#endif

检查预处理器输出

若要准确查看编译器将要编译的内容,请使用 -E 只运行预处理器。

它会展开所有包含指令、宏和条件指令;当宏行为异常时,这项功能非常有用。

gcc -E app.c | less

实际使用功能开关

一种常见模式是使用单独的配置头文件,为整个项目开启或关闭功能。

修改一个 #define,所有文件中的受保护代码块都会作出响应。这样可以将可选功能与核心代码清晰分离。

#include <stdio.h>
#define FEATURE_LOGGING 1

int main(void) {
#if FEATURE_LOGGING
    printf("logging enabled\n");
#endif
    printf("app ready\n");
    return 0;
}

快速检查

请预测命令行定义的行为。

回顾

现在,您已经能够控制条件编译:

  • #ifdef/#ifndef 用于测试宏是否已定义
  • #if/#elif/#else 用于计算常量表达式,并可结合 defined()
  • -DNAME 从命令行定义宏,以切换功能
  • 预定义的平台宏支持可移植代码;包含保护可防止重复包含

下一步:组织跨多个文件的代码。

常见问题解答

「条件编译」课时是免费的吗?

是的 — 「条件编译」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「条件编译」这节课中我会学到什么?

ifdef 与宏 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「条件编译」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 条件编译
  2. 多文件项目
  3. Makefile
  4. 静态库与共享库
← 返回 C Academy