D.C*_*.C. 14 c debugging clang
我经常发现自己编写辅助调试器方法,返回一个可打印的字符串,给定一些枚举值.这样做的原因是当你通常记录枚举时,你得到的只是一个数字.我讨厌不得不回到我的来源找出那个枚举是什么.所以我会做类似的事情
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));
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,有没有办法避免编写所有这些帮助代码,只是为了看到枚举的标签值?
谢谢
Leu*_*nko 22
如果你愿意编写让其他开发人员哭的"顽皮"代码,那么是的.试试这个:
#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
)
Run Code Online (Sandbox Code Playgroud)
你显然需要一个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__)
Run Code Online (Sandbox Code Playgroud)
应该很明显如何将该循环扩展为具有更长的上限,但是这个答案的空间考虑因素.只要您愿意将额外的迭代复制并粘贴到此位,循环就可能有效.
对于非调试版本,请#ifdef选择没有第二行的ENUM版本.
编辑:从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)
)
Run Code Online (Sandbox Code Playgroud)
如果您在其他人必须维护的代码中使用此类内容,我无法保证您的人身安全.
一种更简单的方法是设置一个字符串文字数组,根据它们在数组中的位置复制标签,例如
char *enumlabels[] = { NULL, "KOne", "KTwo", "KThree"};
Run Code Online (Sandbox Code Playgroud)
在这里,您需要填充间隙以使枚举值与数组位置匹配.
或者,更好的是,对于具有指定初始化程序的C99:
char *enumlabels[] = { [1] = "KOne", [2] = "KTwo", [3] = "KThree"};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,只要首先使用枚举声明,就可以直接将数组下标交换为枚举值,以使其更清晰,例如{ [kOne] = "kOne", ... }.
然后MyEnum e你可以使用printf("%s\n", enumlabels[e]);或者其他一些.
我写了一些代码来更好地演示这个:
typedef enum {
white = 1,
red = 2,
green = 4,
blue = 8,
black = 16
} Colour; // be sure to update array below!
char *enum_colours[] = { [white] = "white", [red] = "red", [green] = "green",
[blue] = "blue", [black] = "black" };
Colour c = blue;
printf("The label for %d is %s\n", c, enum_colours[c]);
Run Code Online (Sandbox Code Playgroud)
Output: The label for 8 is blue
如果你有巨大的枚举常量(例如32767),由于所需的数组大小,这显然不是一个理想的解决方案.如果没有指定的初始化程序,您可以直接分配数组值,如果更费力,使用enum_colours[white] = "white";等等,但仅限于函数.
| 归档时间: |
|
| 查看次数: |
1776 次 |
| 最近记录: |