遇到了一个宏没有完全展开的情况。
#include <stdlib.h> #include <stdio.h> /* Use printf inside the definition */ #define PRINTF(fmt, args...) do { printf(fmt, ##args); } while (0) /* Make printf represent as the encapsulated print */ #define printf PRINTF int main(int argc, char* *argv) { int p = 100; printf("p = %d\n", *p); return EXIT_SUCCESS; }
在PRINTF里用到了printf这个名字。然后想又用printf作为标准名称,实际指向经过封装的PRINTF。
结果会出现PRINTF函数未定义的情况。
分析原因应该是
1. 宏展开时预处理器遇到printf按最近的解释执行。发现可以用PRINTF,(第一层展开)
2. 但是准备展开PRINTF时发现PRINTF的定义包含printf,如果允许执行第二层展开。则按照这个允许的逻辑必须执行第三层展开 。如此会构成死循环,所以中止。(第二层展开中止)
改动最里层的宏定义后,可以正常执行展开。
#include <stdlib.h> #include <stdio.h> #include <stdarg.h> int printf2(char const *fmt, ...) { int n = 0; va_list args; va_start(args, fmt); n = vprintf(fmt, args); va_end(args); return n; } /* Use printf inside the definition */ #define PRINTF(fmt, args...) do { printf2(fmt, ##args); } while (0) /* Make printf represent as the encapsulated print */ #define printf PRINTF int main(int argc, char* *argv) { int p = 100; printf("p = %d\n", p); return EXIT_SUCCESS; }
相关推荐
开发者可以定义自己的宏,这些宏在编译时被展开,形成最终的C代码,从而实现了LISP式的函数式编程和动态代码生成。 **CSP的核心特点** 1. **元编程能力**:由于CSP基于C预处理器,它允许在编译时执行代码,可以...
- 当宏参数不是`#`或`##`时,例如`MUL(a, b)`,宏参数会在使用之前完全展开。所以,`MUL(TOW, TOW)`会先展开`TOW`,然后进行计算,得到`(2)*(2)`。 - 当有`#`或`##`时,宏参数不会被进一步展开。例如,`STR(INT_MAX)...
宏参数的预扫描(prescan)是指在宏展开时,参数首先会被完全展开。然而,如果参数在`#`或`##`操作符后面,那么它不会被展开。这在创建类似于`TO_STRING`的宏时特别有用,该宏可以将宏名转换为字符串,帮助开发者...
C语言是一种强大的编程语言,因其灵活性和效率深受程序员喜爱,但它同时也存在一些缺陷和陷阱,对初学者和经验不足的开发者来说,如果不了解这些潜在问题,可能会导致程序错误或者难以维护。以下是对C语言中的一些...
然而,滥用宏可能导致代码难以理解和维护,因为宏的展开不受作用域限制,且不进行类型检查。 #### 5. **函数与递归** C语言支持函数式编程,函数可以返回值并接受参数。递归是一种强大的编程技术,通过函数调用...
### STM32不完全手册知识点概述 #### 一、硬件篇 **1.1 ALIENTEK Mini STM32开发板简介** - **开发板特点**:ALIENTEK Mini STM32开发板是一款专为初学者设计的小型化、功能丰富的STM32开发平台。 - **核心处理器...
数组名在C语言中其实是一个指向首元素的指针,但它们并不完全相同。混淆数组和指针可能导致错误,如试图改变数组长度,或者使用不正确的索引操作。 4. **内存管理**: C语言没有自动垃圾回收机制,程序员需要手动...
预处理指令需要注意的是,带参数的宏在展开之前不会进行参数表达式的计算。位运算的学习关键在于理解数据在内存中的表示形式和位运算的具体规则。文件操作涉及到文件的打开、关闭、读写等基本操作,是进行实际项目...
16. 宏定义和函数调用:宏定义F(X,Y)会展开为X*Y,因此在调用F(a+b,a-b)时,实际调用的是3*4=12。正确答案是A。 17. 多维数组的遍历和输出:通过多维数组的遍历,输出m[k][i]的值,其中k=2,i从0到2。正确答案是D。...
3. **数组与指针的关系**:数组名在很多情况下可以看作是指向其首元素的指针,但这并不意味着它们完全相同。例如,数组长度信息在指针中是丢失的,可能导致越界访问。 4. **内存管理**:动态内存分配(如`malloc`、...
STM32不完全手册是为嵌入式系统开发者提供的一份详细资料,专注于STM32系列微控制器,尤其是STM32F103型号。STM32是由意法半导体(STMicroelectronics)推出的基于ARM Cortex-M内核的微控制器系列,广泛应用于各种...
11. 宏定义与宏展开:题目中的宏`MUL1`和`MUL2`分别代表直接相乘和带括号的相乘。在宏展开时,`3+2`和`5+8`会被计算,因此`x=MUL1(3+2,5+8)`相当于`x=5*13`,`y=MUL2(3+2,5+8)`等同于`(5)*(13)`。所以`x`和`y`的值...
《高质量程序设计指南 C++_C语言(林锐著-超星完全版)》是一部针对C++和C语言编程的深度指南,由知名程序员林锐撰写。这本书旨在帮助读者掌握这两种语言的核心概念、最佳实践以及高级特性,从而编写出高质量、高效、...
宏展开产生的代码过长。尝试简化宏的使用。 #### 60. 参数数量不匹配 (Mismatched number of parameters in definition) 函数定义中的参数数量与实际调用时不一致。确保函数定义和调用时的参数数量一致。 #### 61...
然而,尽管C语言在表面上看起来简洁明了,但在其深处隐藏着许多复杂的概念和技术细节,这些正是许多程序员在面试或实际工作中难以完全掌握的部分。 #### C语言的重要性和难点 C语言的重要性在于它的高效性和灵活性...
- C) 当宏被展开后,实际执行的是`3 * 4`。 - D) 当宏被展开后,实际执行的是`3 * 4`。 **13. 函数参数传递** - **题目描述:** ```c void func(int *a, int b[]) { b[0] = *a + 6; } main() { int a, b[5...
2. **宏的参数**: 宏定义中的`A`和`B`作为参数传递,在宏展开时会被替换为实际的表达式。 - 使用括号将参数包围起来是为了避免宏展开时可能出现的语法错误。 3. **注意事项**: - 宏定义不会进行类型检查,因此...