【C】预处理指令 #define, #include, #if...#elif...#else...#endif

发布时间:2024年01月12日

C 预处理

预处理是C语言编译过程的第一个阶段,它主要由预处理器(Preprocessor)完成。

预处理指令#符号开头,不是C语句,是在编译之前由预处理器处理的命令。

常用预处理指令:#define, #include, #if…#elif…#else…#endif等

1 #define

#define 是C语言预处理器提供的指令,用于定义宏

宏是一种简单的文本替换机制,在编译前将源代码中的宏名替换为对应的宏值或代码片段。

1)基本语法
#define 宏名 替换文本

宏名: 通常是一个标识符,命名规则与变量相同。

替换文本: 可以是常量表达式语句代码块,用于替换宏名。

2)常量宏
#define PI 3.14159

这是最简单的宏定义,将 PI 定义为一个常量,所有出现 PI 的地方都会被替换为 3.14159

3)表达式宏
#define SQUARE(x) ((x) * (x))

int result = SQUARE(5);  // 编译时会被替换为 int result = ((5) * (5));

这个宏用于计算传入参数的平方,是一个带有表达式的宏。

4)语句宏
#define PRINT_MESSAGE() printf("Hello, World!\n")

PRINT_MESSAGE();  // 编译时会被替换为 printf("Hello, World!\n");

这个宏定义了一个打印消息的语句,可以在代码中使用 PRINT_MESSAGE() 来替代实际的 printf 语句。

5)代码块宏
#define MAX(a, b) \
    ({ \
        typeof(a) _a = (a); \
        typeof(b) _b = (b); \
        _a > _b ? _a : _b; \
    })
    
int max_value = MAX(10, 20);  // 编译时会被替换为 int max_value = ({ typeof(10) _a = (10); typeof(20) _b = (20); _a > _b ? _a : _b; });

这是一个用于获取两个数中较大值的宏,使用了代码块,其中包含了局部变量的定义和比较操作。

6)总结

宏虽然有其用处,但在实际编程中应慎重使用,确保宏的使用不会导致代码可读性下降或产生难以维护的问题。

在实际编程中,尽量使用函数代替宏,以提高代码的可读性和维护性。

2 #include

#include 是C语言预处理器指令之一,用于包含外部文件的内容。

1)基本语法
#include <header_file.h>
#include "header_file.h"
  • 尖括号 <>: 用于包含系统提供的头文件,通常是标准C库的头文件。

  • 双引号 "": 用于包含用户自定义的头文件,通常是项目内部的头文件。

  • 当使用尖括号 <> 时,编译器通常会在系统的标准头文件目录中搜索头文件。

  • 当使用双引号 "" 时,编译器会先在当前源代码文件所在的目录搜索,然后在系统的标准头文件目录中搜索。

2)头文件的作用

头文件是C语言中一种用于组织代码的文件。

头文件中可以包含变量、函数、结构体、宏等的声明和定义

这样,在其他源文件中,只需要包含头文件就可以使用这些声明和定义,而无需重新编写。

// sample.h

// 函数声明
void printMessage();

// 宏定义
#define PI 3.14159

// 结构体声明
struct Point {
    int x;
    int y;
};
3)头文件的保护

为了防止头文件被多次包含,常常在头文件的开头和结尾使用预处理器指令进行保护。

// sample.h
#ifndef SAMPLE_H
#define SAMPLE_H

// 头文件内容

#endif  // SAMPLE_H

这样,即使同一个头文件被多次包含,也只会在第一次包含时展开。

  • #ifndef#endif 之间的部分是头文件的实际内容。
  • #ifndef 是条件编译指令,用于判断是否定义了宏 SAMPLE_H,如果未定义,则表示这是第一次包含,执行其中的内容。如果已定义该宏,说明头文件已包含过,不再执行后面内容。
  • #define 用于定义宏 SAMPLE_H
  • #endif 表示条件编译结束。
4)示例
// sample.h

#ifndef SAMPLE_H
#define SAMPLE_H

// 函数声明
void printMessage();

// 宏定义
#define PI 3.14159

// 结构体声明
struct Point {
    int x;
    int y;
};

#endif  // SAMPLE_H
// main.c

#include <stdio.h>
#include "sample.h"

int main() {
    printMessage();
    printf("Value of PI: %f\n", PI);

    struct Point p;
    p.x = 10;
    p.y = 20;

    return 0;
}

上述示例展示了一个简单的头文件,其中包含了函数声明、宏定义和结构体声明。在主程序中使用 #include 引入了这个头文件,使得主程序可以使用头文件中定义的内容。

5)头文件设计原则

包含必要内容: 头文件应该只包含其他源文件需要的声明、定义和结构体等内容,避免将不必要的信息暴露给其他文件

保持简洁: 头文件应该保持简洁,避免包含过多的内容。过大的头文件可能会导致编译时间的增加。

使用预处理器保护: 使用条件编译指令(#ifndef, #define, #endif)来防止头文件被多次包含。

3 #if、#ifdef、ifndef、#elif、#else、#endif

#if#ifdef#ifndef#elif#else#endif 是C语言中的预处理指令,用于条件编译

汇总:

  • #if 用于基于条件,来判断是否编译特定的代码块。
  • #ifdef#ifndef 分别用于检查一个宏是否已经被定义或尚未被定义。
  • #elif 允许在前面的条件不满足时,指定一个新的条件。
  • #else 用于在前面的条件不满足时执行另一段代码。
  • #endif 用于结束条件编译块,必须与之前的 #if#ifdef#ifndef#elif#else 配对使用。
1)#if 指令

#if 指令用于基于条件判断是否编译特定的代码块。条件为一个常量表达式,如果该表达式为真(非零),则执行后面的代码块。

示例:

#define DEBUG 1

#if DEBUG
    printf("Debug mode is enabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义为非零值,就会编译 printf 语句。

2)#ifdef#ifndef 指令

#ifdef(if defined)指令用于检查一个宏是否已经被定义。

#ifndef(if not defined)指令用于检查一个宏是否尚未被定义。

#ifdef MACRO
   // 如果 MACRO 宏已经被定义,执行这部分代码
#endif


#ifndef MACRO
   // 如果 MACRO 宏尚未被定义,执行这部分代码
#endif

示例:

#define DEBUG

#ifdef DEBUG
    printf("Debug mode is enabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义,就会编译 printf 语句。

3)#elif 指令

#elif 指令是 #else#if 的组合,用于指定一个新的条件,如果前面的 #if#elif 条件不满足,且当前条件为真,则执行后面的代码块。

示例:

#define DEBUG_LEVEL 2

#if DEBUG_LEVEL == 1
    printf("Debug level is 1\n");
#elif DEBUG_LEVEL == 2
    printf("Debug level is 2\n");
#else
    printf("Unknown debug level\n");
#endif

在这个例子中,根据 DEBUG_LEVEL 的值不同,选择性地编译不同的 printf 语句。

4)#else 指令

#else 指令用于在前面的条件均不满足时,执行另一段代码。

示例:

#define DEBUG

#ifdef DEBUG
    printf("Debug mode is enabled\n");
#else
    printf("Debug mode is disabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义,就会编译第一个 printf 语句,否则编译第二个 printf 语句。

5)#endif 指令

#endif 指令用于结束条件编译块,必须与之前的 #if#ifdef#ifndef#elif#else 配对使用。

示例:

#define DEBUG

#ifdef DEBUG
    printf("Debug mode is enabled\n");
#else
    printf("Debug mode is disabled\n");
#endif

在这个例子中,#endif 结束了条件编译块。

文章来源:https://blog.csdn.net/weixin_44029896/article/details/135555858
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。