2014-01-20 32 views
1

我有一个工作使静态库更安全,为此我需要替换格式化的字符串printf,使它们在编译的静态库中以不同方式出现,为此要发生它必须在预处理器阶段完成。在GCC中调用预处理器VARIADIC MACROS

我做什么(和它的实际工作在Visual Studio)是以下(,它仅仅是一个伪例如):

char * my_array[] = {"abcd", "a %d", " b %d %s "}; 
#define GENERIC_ARRAY(x) my_array[x] 

#define VARIADIC_DEBUG_PRINT(...) DebugPrintFunction (__FILE__, __LINE__, __func__, __VA_ARGS__) 
#define PRINT_BY_LEVEL(x)   VARIADIC_DEBUG_PRINT x 
#define REPLACE_STRING(x,...)  PRINT_BY_LEVEL((GENERAL_LEVEL,GENERIC_ARRAY(__COUNTER__),__VA_ARGS__)) 

#define MY_PRINTF(x,...)  REPLACE_STRING((void*)0,(void*)0,__VA_ARGS__) 

这一切开销是我欺骗编译器接受不带任何参数,除了打印字符串

所以在我的main.c测试时,我尝试以下和它的工作:

MY_PRINTF("Hello World"); 
MY_PRINTF("My Val %d", i); 
MY_PRINTF("MY VAL %d My String %s", i, s); 

但切换到GCC的时候,他不喜欢在第一次打印,即格式:

MY_PRINTF("Hello World"); 

,并引发了我的编译错误:

error: expected expression before ')' token 

任何想法如何我可以欺骗编译器并接受它?或者更好的想法如何在编译后安全地重命名字符串?

+0

你可能想看看预处理的代码。 – PlasmaHH

+0

'MY_PRINTF(“我的Val%d”,i)的输出是什么;'?说我= 7? – anishsane

+0

输出将是:a 7 – Fluffy

回答

4

你可以尝试这样的:

#include <stdio.h> 
#define PRINT(x, ...) printf(x, ##__VA_ARGS__) 

int main (int argc, char *argv[]) { 
    PRINT("Hello\n"); 
    PRINT("World %d\n", 42); 
    return 0; 
} 

它与GCC 4.8(与早期版本的尝试,但它应该也可以工作)

+0

但我需要插入我的新字符串,而不是旧字符串,并且它不会在您的示例中发生... – Fluffy

+1

这个想法是使用'## __ VA_ARGS__'而不是'__VA_ARGS__'在你的宏。当'__VA_ARGS__'为空时,这可避免包含尾随逗号。 在这种情况下,'PRINT(“Hello \ n”)'扩展为'printf(“Hello \ n”)'而不是'printf(“Hello \ n”,)'这会导致**错误: ''''令牌** gcc错误之前的预期表达式。 – NiBZ

+0

了解为什么''## _ VA_ARGS__''黑客工作:https://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html – Tibo

1

使用##__VA_ARGS__,您可以尝试:

#define MY_PRINTF(x, ...) \ 
    VARIADIC_DEBUG_PRINT(GENERAL_LEVEL, GENERIC_ARRAY(__COUNTER__), (void*)0, (void*)0, ##__VA_ARGS__)