有没有什么编译器/预处理技巧可以用来调试和打印枚举的名称? [英] Are there any compiler / preprocesser tricks to debug print an enum's name?

查看:28
本文介绍了有没有什么编译器/预处理技巧可以用来调试和打印枚举的名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常发现自己编写帮助器调试器方法,这些方法在给定某个枚举值的情况下返回一个可打印的字符串。这是因为当您通常记录枚举时,您得到的实际上只是一个数字。我讨厌回到我的来源去找出那个枚举是什么。所以我会做一些类似

的事情
typedef enum
{
   kOne = 1,
   kTwo,
   kThree,
}
MyEnum;

NSString *debugStringForEnum(MyEnum e)
{
    switch ( e )
        case kOne:
            return @"One";
        case kTwo:
            return @"Two";
        ....
}

....
NSLog(@"My debug log: %@", debugStringForEnum(someVariable));

所以我的问题是,有没有什么方法可以避免编写所有这些帮助器代码,只为了查看枚举的标签值?

谢谢

推荐答案

如果您愿意编写让其他开发人员流泪的"淘气"代码,那么可以。试试这个:

#define ENUM(name, ...) typedef enum { M_FOR_EACH(ENUM_IDENTITY, __VA_ARGS__) } name; 
char * name ## _DEBUGSTRINGS [] = { M_FOR_EACH(ENUM_STRINGIZE, __VA_ARGS__) };

#define ENUM_IDENTITY(A) A,
#define ENUM_STRINGIZE(A) #A,

ENUM(MyEnum,
        foo, bar, baz, boo
        )
您显然需要一个For-Each宏才能使其工作。这里有一个简单的例子:

#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N

#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B

#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)

#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
#define M_FOR_EACH_6(ACTN, E, ...) ACTN(E) M_FOR_EACH_5(ACTN, __VA_ARGS__)
#define M_FOR_EACH_7(ACTN, E, ...) ACTN(E) M_FOR_EACH_6(ACTN, __VA_ARGS__)
#define M_FOR_EACH_8(ACTN, E, ...) ACTN(E) M_FOR_EACH_7(ACTN, __VA_ARGS__)
#define M_FOR_EACH_9(ACTN, E, ...) ACTN(E) M_FOR_EACH_8(ACTN, __VA_ARGS__)
#define M_FOR_EACH_10(ACTN, E, ...) ACTN(E) M_FOR_EACH_9(ACTN, __VA_ARGS__)
如何扩展该循环以获得更长的上限应该是显而易见的,但是.此答案的空间考虑因素。只要您愿意将额外的迭代复制并粘贴到此位中,循环就可能很长。

对于非调试版本,让#ifdef选择不带第二行的ENUM版本。


edit:要从teppic窃取指定的初始值设定项,这里有一个更可怕的版本,它也适用于无序的初始值设定值:

#define ENUM(name, ...) typedef enum { M_FOR_EACH(ENUM_ENAME, __VA_ARGS__) } name; 
char * name ## _DEBUGSTRINGS [] = { M_FOR_EACH(ENUM_ELEM, __VA_ARGS__) };

#define ENUM_ENAME(A) M_IF(M_2ITEMS(M_ID A), (M_FIRST A = M_SECOND A), (A)),
#define ENUM_ELEM(A) M_IF(M_2ITEMS(M_ID A), ([M_FIRST A] = M_STR(M_FIRST A)), ([A] = M_STR(A))),

#define M_STR(A) M_STR_(A)
#define M_STR_(A) #A
#define M_IF(P, T, E) M_CONC(M_IF_, P)(T, E)
#define M_IF_0(T, E) M_ID E
#define M_IF_1(T, E) M_ID T
#define M_2ITEMS(...) M_2I_(__VA_ARGS__, 1, 0)
#define M_2I_(_2, _1, N, ...) N
#define M_FIRST(A, ...) A
#define M_SECOND(A, B, ...) B
#define M_ID(...) __VA_ARGS__

ENUM(MyEnum,
        foo, bar, baz, boo
        )

ENUM(NotherEnum,
        A, B, (C, 12), D, (E, 8)
        )

如果您在其他人必须维护的代码中使用此类内容,我无法保证您的人身安全。

这篇关于有没有什么编译器/预处理技巧可以用来调试和打印枚举的名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆