我写了一点C语言,我能很好地阅读它,对它的功能有一个大致的了解,但每次我遇到一个宏,它都会让我完全不知所措.最后,我不得不记住宏是什么,并在阅读时在脑海中替换它.我遇到的那些直观易懂的函数总是像小函数一样,所以我总是想知道为什么它们不只是函数.

我能理解在预处理器中为调试或跨平台构建定义不同构建类型的需要,但定义任意替换的能力似乎只会让已经很难理解的语言变得更难理解.

为什么要为C引入如此复杂的预处理器?有没有人举过一个使用它的例子,让我明白为什么它似乎仍然被用于简单的if#debug风格的条件编译之外的目的?

编辑:

读了很多答案后,我还是不明白.最常见的答案是内联代码.如果inline关键字不能做到这一点,那么要么它有很好的理由不这样做,要么实现需要修复.我不明白为什么需要一种完全不同的机制来表示"真正内联这段代码"(除了内联出现之前编写的代码).我也不理解有人提到的"如果放在函数里太傻了"的 idea .当然,任何接受输入并产生输出的代码都最好放在函数中.我想我可能没有理解它,因为我不习惯于编写C语言的微优化,但是预处理器感觉就像是几个简单问题的复杂解决方案.

推荐答案

最后,我不得不记住宏是什么,并在阅读时在脑海中替换它.

这似乎不利于宏的命名.我假设如果预处理器是log_function_entry()宏,您就不必模拟它.

我遇到的那些直观和容易理解的函数总是像小的迷你函数,所以我总是想知道为什么它们不只是函数.

通常应该是这样,除非它们需要对通用参数进行操作.

#define max(a,b) ((a)<(b)?(b):(a))

将与<操作员一起在任何类型上工作.

除了功能之外,宏还允许您使用源文件中的符号执行操作.这意味着您可以创建一个新的变量名,或者引用宏所在的源文件和行号.

在C99中,宏还允许调用变量函数,例如printf

#define log_message(guard,format,...) \
   if (guard) printf("%s:%d: " format "\n", __FILE__, __LINE__,__VA_ARGS_);

log_message( foo == 7, "x %d", x)

这种格式的工作原理类似于printf.如果guard为true,它将输出消息以及打印消息的文件和行号.如果它是一个函数调用,它将不知道调用它的文件和行,而使用vaprintf将需要更多的工作.

C++相关问答推荐

Mise()在虚拟内存中做什么?

VS代码C/C++扩展intellisense无法检测环境特定函数'

试图从CSV文件中获取双精度值,但在C++中始终为空

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

什么是.c.h文件?

编译器如何处理具有更复杂值的枚举?

致命错误:ASM/rwan ce.h:没有这样的文件或目录.符号链接还不够

如何用C语言为CLI应用程序编写按键检测系统?

错误...的多个定义(&Q)首先在这里定义&

如何将C中的两个字符串与从文件接收的字符串中的字符数进行比较

C语言中浮点数的取整方式浮点数尾数超过23位时如何取整剩余部分

如何将两个uint32_t值交织成一个uint64_t?

有没有办法减少C语言中线程的堆大小?

如何在不更改格式说明符的情况下同时支持双精度和长双精度?

Malloc和对齐

如果类型是新的,offsetof是否与typeof一起工作?

在C中使用字符串时是否不需要内存分配?

为什么 Linux 共享库 .so 在内存中可能比在磁盘上大?

如何修复数组数据与列标题未对齐的问题?

在链表中插入一个值