gcc编译期打印宏的值

如果我们想知道一个宏的值应该怎么办?

要么在代码里加一句printf

要么在编译的时候gcc -E

第一种方法需要程序运行起来,颇为麻烦

第二种方法无法应付下面这些情况

比如宏的值等于sizeof(struct xxoo)

比如宏本身就是一个复杂的运算(((2U) << (((0+8)+8)+13)) | ((('W')) << (0+8)) | (((7)) << 0) | (((((sizeof(int) == sizeof(int[1]) && sizeof(int) < (1 << 13)) ? sizeof(int) : __invalid_size_argument_for_IOC))) << ((0+8)+8)))


我设计了一个编译期打印宏值的方法,原理是利用gcc函数属性扩展warning和编译期运算

代码show_marco.h

#ifndef _SHOW_MACRO_H_
#define _SHOW_MACRO_H_

/*
SHOW_MSG(expression, true string, false string)
SHOW_MACRO(MACRO_NAME)
SHOW_MACRO(ENUM_NAME)
MACRO2STRING(MACRO_NAME)

zhaoxiaogang 2014-11-18
*/

#define MACRO2STRING_(M) #M
#define MACRO2STRING(M) MACRO2STRING_(M)

#define a_t_t_r(S) __attribute__((warning(S)))

#define SHOW_MSG__(E, S1, S2, N) \
    int str1__##N(void) a_t_t_r(S1); \
    int str2__##N(void) a_t_t_r(S2); \
    int str0__##N(void) { return (E) ? str1__##N() : str2__##N(); } \
    struct stru__##N { unsigned int check_expression : 1 + !(E); };

#define SHOW_MSG_(E, S1, S2, N) SHOW_MSG__(E, S1, S2, N)

#ifdef __COUNTER__
#  define SHOW_MSG(E, S1, S2) SHOW_MSG_(E, S1, S2, __COUNTER__)
#else
#  define SHOW_MSG(E, S1, S2) SHOW_MSG_(E, S1, S2, __LINE__)
#endif

#define j_(v) int show__0x##v(void) a_t_t_r(#v);
j_(0) j_(1) j_(2) j_(3) j_(4) j_(5) j_(6) j_(7) j_(8) j_(9) j_(a) j_(b) j_(c) j_(d) j_(e) j_(f)

#define k_(M,i,j) (((((M)+0ULL)>>((15-0x##i)*4))&0xF)==0x##j ? show__0x##j() : 0) +

#define SHOW_MACRO(M) \
    int M##__eq(void) a_t_t_r(#M" = "MACRO2STRING(M)); \
    int M##__lt(void) a_t_t_r(#M" < 0"); \
    int M##__ge(void) a_t_t_r(#M" >= 0"); \
    int show__##M(void) { \
        return M##__eq() + \
        k_(M,0,0) k_(M,0,1) k_(M,0,2) k_(M,0,3) k_(M,0,4) k_(M,0,5) k_(M,0,6) k_(M,0,7) k_(M,0,8) k_(M,0,9) k_(M,0,a) k_(M,0,b) k_(M,0,c) k_(M,0,d) k_(M,0,e) k_(M,0,f) \
        k_(M,1,0) k_(M,1,1) k_(M,1,2) k_(M,1,3) k_(M,1,4) k_(M,1,5) k_(M,1,6) k_(M,1,7) k_(M,1,8) k_(M,1,9) k_(M,1,a) k_(M,1,b) k_(M,1,c) k_(M,1,d) k_(M,1,e) k_(M,1,f) \
        k_(M,2,0) k_(M,2,1) k_(M,2,2) k_(M,2,3) k_(M,2,4) k_(M,2,5) k_(M,2,6) k_(M,2,7) k_(M,2,8) k_(M,2,9) k_(M,2,a) k_(M,2,b) k_(M,2,c) k_(M,2,d) k_(M,2,e) k_(M,2,f) \
        k_(M,3,0) k_(M,3,1) k_(M,3,2) k_(M,3,3) k_(M,3,4) k_(M,3,5) k_(M,3,6) k_(M,3,7) k_(M,3,8) k_(M,3,9) k_(M,3,a) k_(M,3,b) k_(M,3,c) k_(M,3,d) k_(M,3,e) k_(M,3,f) \
        k_(M,4,0) k_(M,4,1) k_(M,4,2) k_(M,4,3) k_(M,4,4) k_(M,4,5) k_(M,4,6) k_(M,4,7) k_(M,4,8) k_(M,4,9) k_(M,4,a) k_(M,4,b) k_(M,4,c) k_(M,4,d) k_(M,4,e) k_(M,4,f) \
        k_(M,5,0) k_(M,5,1) k_(M,5,2) k_(M,5,3) k_(M,5,4) k_(M,5,5) k_(M,5,6) k_(M,5,7) k_(M,5,8) k_(M,5,9) k_(M,5,a) k_(M,5,b) k_(M,5,c) k_(M,5,d) k_(M,5,e) k_(M,5,f) \
        k_(M,6,0) k_(M,6,1) k_(M,6,2) k_(M,6,3) k_(M,6,4) k_(M,6,5) k_(M,6,6) k_(M,6,7) k_(M,6,8) k_(M,6,9) k_(M,6,a) k_(M,6,b) k_(M,6,c) k_(M,6,d) k_(M,6,e) k_(M,6,f) \
        k_(M,7,0) k_(M,7,1) k_(M,7,2) k_(M,7,3) k_(M,7,4) k_(M,7,5) k_(M,7,6) k_(M,7,7) k_(M,7,8) k_(M,7,9) k_(M,7,a) k_(M,7,b) k_(M,7,c) k_(M,7,d) k_(M,7,e) k_(M,7,f) \
        k_(M,8,0) k_(M,8,1) k_(M,8,2) k_(M,8,3) k_(M,8,4) k_(M,8,5) k_(M,8,6) k_(M,8,7) k_(M,8,8) k_(M,8,9) k_(M,8,a) k_(M,8,b) k_(M,8,c) k_(M,8,d) k_(M,8,e) k_(M,8,f) \
        k_(M,9,0) k_(M,9,1) k_(M,9,2) k_(M,9,3) k_(M,9,4) k_(M,9,5) k_(M,9,6) k_(M,9,7) k_(M,9,8) k_(M,9,9) k_(M,9,a) k_(M,9,b) k_(M,9,c) k_(M,9,d) k_(M,9,e) k_(M,9,f) \
        k_(M,a,0) k_(M,a,1) k_(M,a,2) k_(M,a,3) k_(M,a,4) k_(M,a,5) k_(M,a,6) k_(M,a,7) k_(M,a,8) k_(M,a,9) k_(M,a,a) k_(M,a,b) k_(M,a,c) k_(M,a,d) k_(M,a,e) k_(M,a,f) \
        k_(M,b,0) k_(M,b,1) k_(M,b,2) k_(M,b,3) k_(M,b,4) k_(M,b,5) k_(M,b,6) k_(M,b,7) k_(M,b,8) k_(M,b,9) k_(M,b,a) k_(M,b,b) k_(M,b,c) k_(M,b,d) k_(M,b,e) k_(M,b,f) \
        k_(M,c,0) k_(M,c,1) k_(M,c,2) k_(M,c,3) k_(M,c,4) k_(M,c,5) k_(M,c,6) k_(M,c,7) k_(M,c,8) k_(M,c,9) k_(M,c,a) k_(M,c,b) k_(M,c,c) k_(M,c,d) k_(M,c,e) k_(M,c,f) \
        k_(M,d,0) k_(M,d,1) k_(M,d,2) k_(M,d,3) k_(M,d,4) k_(M,d,5) k_(M,d,6) k_(M,d,7) k_(M,d,8) k_(M,d,9) k_(M,d,a) k_(M,d,b) k_(M,d,c) k_(M,d,d) k_(M,d,e) k_(M,d,f) \
        k_(M,e,0) k_(M,e,1) k_(M,e,2) k_(M,e,3) k_(M,e,4) k_(M,e,5) k_(M,e,6) k_(M,e,7) k_(M,e,8) k_(M,e,9) k_(M,e,a) k_(M,e,b) k_(M,e,c) k_(M,e,d) k_(M,e,e) k_(M,e,f) \
        k_(M,f,0) k_(M,f,1) k_(M,f,2) k_(M,f,3) k_(M,f,4) k_(M,f,5) k_(M,f,6) k_(M,f,7) k_(M,f,8) k_(M,f,9) k_(M,f,a) k_(M,f,b) k_(M,f,c) k_(M,f,d) k_(M,f,e) k_(M,f,f) \
        ((M) < 0 ? M##__lt() : M##__ge()); \
    } \
    struct M##__stru { unsigned int check_macro : 1 + !(M); };

#endif

用法举例

在要打印的源文件中加入

#include "show_macro.h"

SHOW_MACRO(WDIOC_GETTIMEOUT)

这样WDIOC_GETTIMEOUT的值就会以编译warning的形式打印出来

octeon-wdt-main.c:618: In function 'show__WDIOC_GETTIMEOUT':

octeon-wdt-main.c:618: warning: call to 'WDIOC_GETTIMEOUT__eq' declared with attribute warning: WDIOC_GETTIMEOUT = (((2U) << (((0+8)+8)+13)) | ((('W')) << (0+8)) | (((7)) << 0) | (((((sizeof(int) == sizeof(int[1]) && sizeof(int) < (1 << 13)) ? sizeof(int) : __invalid_size_argument_for_IOC))) << ((0+8)+8)))

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x4' declared with attribute warning: 4

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x4' declared with attribute warning: 4

octeon-wdt-main.c:618: warning: call to 'show__0x5' declared with attribute warning: 5

octeon-wdt-main.c:618: warning: call to 'show__0x7' declared with attribute warning: 7

octeon-wdt-main.c:618: warning: call to 'show__0x0' declared with attribute warning: 0

octeon-wdt-main.c:618: warning: call to 'show__0x7' declared with attribute warning: 7

octeon-wdt-main.c:618: warning: call to 'WDIOC_GETTIMEOUT__ge' declared with attribute warning: WDIOC_GETTIMEOUT >= 0

0x0000000040045707就是WDIOC_GETTIMEOUT的值

注意,如果编译信息太多,那么可能需要筛选一下 gcc ... -c octeon-wdt-main.c 2>&1 | grep warning

SHOW_MACRO() 的参数可以是宏 也可以是枚举值

另外, show_macro.h还附送了一个叫 SHOW_MSG(exp, str1, str2) 的宏

exp为编译期可运算的常表达式 当exp结果为真时编译时打印字符串str1 否则打印str2


你可能感兴趣的:(gcc,宏,编译)