C:对预处理器宏感到困惑吗
我使用头文件中的预处理宏向代码中添加了一系列“debug(x)”语句。我还实现了一个切换(通过头文件中的#ifdef/#else结构),可以关闭调试语句。我很难让这个开关工作,我希望有人能找出原因 我没有重新发布实际的代码(很长),而是提供了一个示例(编译) 这是我们的.h文件。它由一个名为“超人”的函数的宏组成。当且仅当.c文件中未定义KRYPTONITE时,才会打印该语句 测试h:C:对预处理器宏感到困惑吗,c,macros,c-preprocessor,C,Macros,C Preprocessor,我使用头文件中的预处理宏向代码中添加了一系列“debug(x)”语句。我还实现了一个切换(通过头文件中的#ifdef/#else结构),可以关闭调试语句。我很难让这个开关工作,我希望有人能找出原因 我没有重新发布实际的代码(很长),而是提供了一个示例(编译) 这是我们的.h文件。它由一个名为“超人”的函数的宏组成。当且仅当.c文件中未定义KRYPTONITE时,才会打印该语句 测试h: #ifndef __test_h__ #define __test_h__ #ifdef KRYPTONIT
#ifndef __test_h__
#define __test_h__
#ifdef KRYPTONITE
#define superman(...)
#else
#define superman(xs) printf("%s\n\n",xs)
#endif
#endif
正如您在下面的案例中所看到的,在.c文件的开头添加“#define KRYPTONITE 1”语句不会关闭“superman”函数(下面的案例2)。然而,如果我们在编译指令中通过一个标志定义KRYPTONITE,我们确实成功地关闭了它(案例3)
我还需要做什么才能通过.c文件中的“#define”语句关闭“superman”函数
案例1:KRYPTONITE未在.c文件中定义(已注释掉)。正如预期的那样,语句将打印出来。(下面是.c文件和输出。) 测试1.c:
#include <stdio.h>
#include "test.h"
//#define KRYPTONITE
int main (int argc, char *argv[])
{
printf("\nSuperman, are you here?\n\n");
superman("I'm here");
return 0;
}
案例2:KRYPTONITE是在我们的.c文件中定义的,但是语句会打印出来 测试2.c:
#include <stdio.h>
#include "test.h"
#define KRYPTONITE
int main (int argc, char *argv[])
{
printf("\nSuperman, are you here?\n\n");
superman("I'm here");
return 0;
}
案例3:KRYPTONITE没有在我们的.c文件中定义,但是我们在编译时通过一个标志来定义它。在这种情况下,超人功能被成功关闭 输出:
dchaudh@dchaudhUbuntu:~/SO$ gcc test1.c -o test1
dchaudh@dchaudhUbuntu:~/SO$ ./test1
Superman, are you here?
I'm here
dchaudh@dchaudhUbuntu:~/SO$
dchaudh@dchaudhUbuntu:~/SO$ gcc test2.c -o test2
dchaudh@dchaudhUbuntu:~/SO$ ./test2
Superman, are you here?
I'm here
dchaudh@dchaudhUbuntu:~/SO$
dchaudh@dchaudhUbuntu:~/SO$ gcc -DKRYPTONITE test1.c -o test3
dchaudh@dchaudhUbuntu:~/SO$ ./test3
Superman, are you here?
dchaudh@dchaudhUbuntu:~/SO$
proeprocessor就像C编译器一样,从上到下扫描文件。这意味着在使用宏之前必须先定义宏 因此,要解决您的问题,请将
\define
放在\include
之前
#include <stdio.h>
#define KRYPTONITE
#include "test.h"
int main (int argc, char *argv[])
{
printf("\nSuperman, are you here?\n\n");
superman("I'm here"); // Doesn't print
return 0;
}
#包括
#定义氪石
#包括“test.h”
int main(int argc,char*argv[])
{
printf(“\n佩尔曼,你在吗?\n\n”);
超人(“我在这里”);//不打印
返回0;
}
不相关,但从技术上讲,根据规范,带有两个前导下划线的符号保留供编译器和标准库使用。使用此类宏进行日志记录的小技巧:C99预处理器支持可变宏,MSVC也有可变宏。扩展中尾随逗号的处理方式略有不同。例如#定义log_printf(l,fmt,…)fprinf(stderr,“%c:”fmt,l,u VA_u参数)
。然而,对于GCC,这需要始终提供额外的参数,MSVC会默默地解决这个问题。但是,GCC有一个扩展名,您可以编写#uu VA_uargs_uu
。@datenwolf目前我在我的变量宏中使用###u VA_uargs_uu(即前面有两个#符号的VA_uargs),它似乎在使用-std=gnu99。你认为这个组合会有什么问题吗?(我目前只是一名C语言的学生,还没有遇到交叉编译器的问题。)我有偏见,但我建议寻找如何更好地实现调试宏的想法。特别是,当调试被禁用时,让编译器完全忽略调试宏是个坏主意。您希望它检查代码的有效性,以便在重新启用调试时,它仍然有效。@DipakC:实际上,在我上面的注释中,第二个
丢失了,它应该是\uu VA_ARGS\uuu
。我不认为这种做法有什么问题,除了你需要GCC。但是,当您已经在执行预处理器黑魔法时,您还可以使用它检测编译器,并适当地定义宏。我所有用C写的东西通常都包含一个头\u compiler.h
,所有的黑魔法都在那里。