Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C:对预处理器宏感到困惑吗_C_Macros_C Preprocessor - Fatal编程技术网

C:对预处理器宏感到困惑吗

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

我使用头文件中的预处理宏向代码中添加了一系列“debug(x)”语句。我还实现了一个切换(通过头文件中的#ifdef/#else结构),可以关闭调试语句。我很难让这个开关工作,我希望有人能找出原因

我没有重新发布实际的代码(很长),而是提供了一个示例(编译)

这是我们的.h文件。它由一个名为“超人”的函数的宏组成。当且仅当.c文件中未定义KRYPTONITE时,才会打印该语句

测试h:

#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
,所有的黑魔法都在那里。