C 语言编程教程

C 语言 - 首页

C 语言基础

C 语言 - 概述 C 语言 - 特性 C 语言 - 发展历史 C 语言 - 环境设置 C 语言 - 程序结构 C 语言 - Hello World C - 编译过程 C - 注释 C - 标记 C - 关键字 C - 标识符 C - 用户输入 C - 基本语法 C - 数据类型 C - 变量 C - 整数提升 C - 类型转换 C - 类型转换 C - 布尔值

C 语言中的常量和文字

C - 常量 C - 字面量 C - 转义序列 C - 格式说明符

C 语言中的运算符

C - 运算符 C - 算术运算符 C - 关系运算符 C - 逻辑运算符 C - 位运算符 C - 赋值运算符 C - 一元运算符 C - 递增和递减运算符 C - 三元运算符 C - sizeof 运算符 C - 运算符优先级 C - 其他运算符

C 语言中的决策

C - 决策 C - if 语句 C - if...else 语句 C - 嵌套 if 语句 C - switch 语句 C - 嵌套 switch 语句

C 语言中的循环

C - 循环 C - While 循环 C - For 循环 C - Do...while 循环 C - 嵌套循环 C - 无限循环 C - Break 语句 C - Continue 语句 C - goto 语句

C 语言中的函数

C - 函数 C - Main 函数 C - 按值调用函数 C - 按引用调用函数 C - 嵌套函数 C - 可变参数函数 C - 用户定义函数 C - 回调函数 C - return 语句 C - 递归

C 语言中的作用域规则

C - 作用域规则 C - 静态变量 C - 全局变量

C 语言中的数组

C - 数组 C - 数组的属性 C - 多维数组 C - 将数组传递给函数 C - 从函数返回数组 C - 可变长度数组

C 语言中的指针

C - 指针 C - 指针和数组 C - 指针的应用 C - 指针运算 C - 指针数组 C - 指向指针的指针 C - 将指针传递给函数 C - 从函数返回指针 C - 函数指针 C - 指向数组的指针 C - 指向结构体的指针 C - 指针链 C - 指针 vs 数组 C - 字符指针和函数 C - NULL 指针 C - void 指针 C - 悬垂指针 C - 解引用指针 C - Near、Far 和 Huge 指针 C - 指针数组的初始化 C - 指针与多维数组

C 语言中的字符串

C - 字符串 C - 字符串数组 C - 特殊字符

C 语言的结构体和联合

C - 结构体 C - 结构体和函数 C - 结构体数组 C - 自引用结构 C - 查找表 C - 点 (.) 运算符 C - 枚举(或 enum) C - 结构填充和打包 C - 嵌套结构 C - 匿名结构和联合 C - 联合 C - Bit 位字段 C - Typedef

C 语言中的文件处理

C - 输入和输出 C - 文件 I/O(文件处理)

C 语言中的预处理器

C - 预处理器 C - #pragma 编译指示 C - 预处理器操作符 C - 宏 C - 头文件

C 语言中的内存管理

C - 内存管理 C - 内存地址 C - 存储类

C 其他主题

C - 错误处理 C - 可变参数 C - 命令执行 C - 数学函数 C - static 静态关键字 C - 随机数生成 C - 命令行参数

C 语言编程资源

C语言问题与解答答案 C语言快速指南 C语言速查表 C语言实用资源 C语言讨论


C 语言中的宏

C 语言中的宏是赋予特定常量值或代码语句的名称,在编译处理器之前,这些常量值或代码会被替换为相应的值/代码。 C 宏 使用 #define 预处理器指令定义。

对于代码可重用性、定义常量值、定义内联函数和条件编译非常有用。

以下是我们将在本教程中介绍的不同类型的 C 宏 -

  • 类对象宏
  • 类函数宏
  • 链式宏
  • 可变参数宏
  • 预定义宏

类对象宏

定义常量的宏是类对象宏。

语法

使用以下语法 -

#define name value

类对象宏示例

在以下示例中,我们定义了一个类对象宏 -

#include <stdio.h>

// 定义宏
#define PI 3.14
#define MAX 10

int main() {
   // 打印值
   printf("Value of PI = %d
", PI);
   printf("Value of MAX = %d
", MAX);

   return 0;
}

类函数宏

要定义类函数宏,请使用相同的"#define"指令,但在宏名称后紧接着一对括号,并带有一个或多个参数。只有当宏名称后跟一对括号时,才会展开此类宏。

预处理器展开此类宏时,会将指定的参数合并到替换文本中。类函数宏通常称为带参数(或实参)的宏。

语法

类函数宏的定义如下 -

#define macro_name([parameter_list]) replacement_text

类函数宏示例

下面给出了一个类函数宏的示例 -

#include <stdio.h>

#define square(x) ((x) * (x))

int main(){

   int x = 5;
   printf("x: %d 	Square of x: %d", x, square(x));
   return 0;
}

输出

运行此代码时,将产生以下输出 -

x: 5 	Square of x: 25

定义类函数宏的规则

一些定义函数的规则也适用于宏 -

  • 宏可以不带参数定义
  • 宏可以带有固定数量的参数定义
  • 宏可以带有可变数量的参数定义

例如,当您使用这样的宏时,逗号分隔的参数列表必须包含与宏定义中的参数数量相同的参数。

不带参数的类函数宏

类函数宏也可以不带参数定义。

示例 1

以下示例展示了如何使用不带参数的宏 -

#include <stdio.h>

#define MESSAGE() printf("Hello World");

int main() {

   int x = 5;
   MESSAGE();
   return 0;
}

输出

运行代码并检查其输出 −

Hello World

一些标准库也提供了宏定义。例如,getchar() 宏展开后,实现了 getc() 函数,如下所示:-

#define getchar() getc(stdin)

类似地,putchar() 宏封装了 putc() 函数:-

#define putchar(x) putc(x, stdout)

示例 2

以下程序定义了一个名为 LOOP(x) 的宏,并运行一个 for 循环,循环次数作为其参数:-

#include <stdio.h>

#define LOOP(x) {\
   for (int i = 1; i <= x; i++)\
   printf("Iteration no: %d
", i);\
}

int main() {

   int x = 3;
   LOOP(x);
}

输出

运行此代码时,将产生以下输出 -

Iteration no: 1
Iteration no: 2
Iteration no: 3

链式宏

当一个宏嵌套在另一个宏中时,它们被称为链式宏。

链式宏示例

以下示例展示了如何使用链式宏 -

#include <stdio.h>

#define PI 3.142
#define CIRCUMFERENCE(x) (2*PI*x)

int main(){

   int x = 5;
   printf("Circumference of a circle with radius %d is %f", x, CIRCUMFERENCE(x));
   return 0;
}

输出

运行此代码时,将产生以下输出 -

Circumference of a circle with radius 5 is 31.420000

可变参数宏

您还可以定义具有可变数量参数的宏或可变参数宏。具有可变长度参数的宏是一种允许宏接受任意数量参数的功能。您可以将位置参数和关键字参数传递给宏。

定义可变参数宏时,省略号 () 作为参数,用于捕获可变数量的参数。要使用可变参数宏,可以将省略号指定为宏定义中的最后一个形式参数。此标记序列将替换宏主体中出现的标识符 __VA_ARGS__。

__VA_ARGS__ 将被替换为与省略号匹配的所有参数,包括它们之间的逗号。请注意,可变参数宏只能在兼容 C99 及以上版本的 C 编译器中使用。

可变参数宏示例

请看以下示例 -

#include <stdio.h>

#define MAX_ARGS 5 // 定义允许的最大参数数量
#define ARGS(x, ...) do {\
   printf("%d
", ##__VA_ARGS__); \
} while (0)

int main() {

   ARGS(1, 2, 3); 		// 3 参数
   ARGS(1, 2, 3, 4, 5, 6);	// 6 参数 
   return 0;
}

输出

运行代码并检查其输出 −

2
2

预定义宏

ANSI C 定义了许多宏。虽然每个宏都可以在编程中使用,但不应直接修改预定义宏。

描述
__DATE__ 以字符形式表示的当前日期,格式为"MMM DD YYYY"。
__TIME__ 以字符形式表示的当前时间,格式为"HH:MM:SS"。
__FILE__ 包含当前文件名的字符串字面量。
__LINE__ 它包含当前行号,为十进制常量。
__STDC__ 当编译器符合 ANSI 标准时,定义为 1。

示例

以下示例演示了如何在 C 程序中使用预定义宏 -

#include <stdio.h>

int main() {

   printf("File :%s
", __FILE__ );
   printf("Date :%s
", __DATE__ );
   printf("Time :%s
", __TIME__ );
   printf("Line :%d
", __LINE__ );
   printf("ANSI :%d
", __STDC__ );
}

输出

运行此代码时,将产生以下输出 -

File: main.c
Date: Mar 6 2024
Time: 20:12:19
Line: 8
ANSI: 1