`
chenqi210
  • 浏览: 76786 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C宏不完全展开的情况

阅读更多

遇到了一个宏没有完全展开的情况。

#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;
}

 

 

分享到:
评论

相关推荐

    内联函数inline与宏定义深入解析

    内联函数的优越性:一:inline定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换(像宏定义一样展开),没有了调用的开销,效率很高。二:类的内敛函数是一个真正的函数。三:使用内联函数inline...

    图像处理的 相关资料

    宏展开后完全包含在一对括号中,而且参数也包含在括号中,这样就保证了宏和参数的完整性。看一个用法: int num=8+2; volume=Cube(num); 展开后为(8+2)*(8+2)*(8+2); 如果没有那些括号就变为8+2*8+2*8+2了。 ...

    宋劲彬的嵌入式C语言一站式编程

    9. 不完全类型和复杂声明 24. 函数接口 1. 本章的预备知识 1.1. strcpy与strncpy 1.2. malloc与free 2. 传入参数与传出参数 3. 两层指针的参数 4. 返回值是指针的情况 5. 回调函数 6. 可变参数 25. C标准库 1. 字符...

    recursive-macroexpansion:提供另一个 `macroexpand`

    递归宏展开 另一个宏扩展系统提供了更简单的编译时错误处理。 Recursive-Macroexpansion 的扩展算法与 Common Lisp 的宏扩展完全不同,它基于macroexpand-1和macroexpand 。 应用程序接口 导出了四个函数/宏。 ...

    Source Insight Token Macro

    因为source insight不展开宏,导致WRK、CRT、C头文件等解析不完全,用SI的Token Macro可以解决这个问题。 使用方法很简单,多务必把它们重命名为C.tom,并放到对应工程目录下!! 原理请看:...

    emule0.50a-Xtreme8.1源码(VS2008下可无错编译成功)

    错误 140 fatal error C1057: 宏展开中遇到意外的文件结束 d:\eMule\srchybrid\BaseClient.cpp 4832 emule 此类错误中,实际上是是两个语法错误,由于太过简单,我与网友都怀疑是作者故意制造的错误,若是完全不懂...

    代码语法错误分析工具pclint8.0

    C语言的灵活性带来了代码效率的提升,但相应带来了代码编写的随意性,另外C编译器不进行强制类型检查,也带来了代码编写的隐患。PCLint识别并报告C语言中的编程陷阱和格式缺陷的发生。它进行程序的全局分析,能识别...

    compile_msg:编译时用户定义的诊断

    compile_note :告诉用户一点信息,但不暗示这是一个问题, compile_warning :告诉用户可能出现问题, compile_error :告诉用户一些错误,编译不会立即停止,而是会在宏展开后任何编译器通过之前停止。...

    【05-面向对象(下)】

    •接口的继承和类继承不一样,接口完全支持多继承,子接口扩展某个父接口将会获得父接口的所有抽象方法,常 量属性,内部类和枚举类定义。 使用接口 •接口可以用于声明引用类型的变量,但接口不能用于...

    PLSQLDeveloper下载

     PL/SQL编辑器,功能强大——该编辑器具有语法加强、SQL和PL/SQL帮助、对象描述、代码助手、编译器提示、PL/SQL完善、代码内容、代码分级、浏览器按钮、超链接导航、宏库等许多智能特性,能够满足要求性最高的用户...

    C#微软培训资料

    18.2 在 C #代码中调用 C++和 VB 编写的组件 .240 18.3 版 本 控 制 .249 18.4 代 码 优 化 .252 18.5 小 结 .254 第五部分 附 录 .255 附录 A 关 键 字.255 附录 B 错 误 码.256 附录 C .Net 名字空间...

    uboott移植实验手册及技术文档

    关,如果没有定义这个宏,系统调用 drivers/nand/nand.c 中的 nand_init();否则调用自己在 本文件中的 nand_init()函数,本例使用后者。fs2410.c代码如下: #if defined(CONFIG_CMD_NAND) typedef enum { NFCE_...

    arcgis工具

    在编辑未完成时按快捷键E切换到选择的环境中去 Z 放大 X 缩小 C 漫游 V显示节点 Ctrl+Z 撤销Ctrl+Y 重做 SpaceBar 暂停捕捉 二、编辑工具: Shift:添加至/取消选择 Ctrl:移动选择锚 N:下一个被选要素 三、用于...

    网管教程 从入门到精通软件篇.txt

    Windows XP(包括 Windows 2000)的控制台命令是在系统出现一些意外情况下的一种非常有效的诊断和测试以及恢复系统功能的工具。小编的确一直都想把这方面的命令做个总结,这次辛苦老范给我们整理了这份实用的秘笈。 ...

Global site tag (gtag.js) - Google Analytics