Enum reflection in C
I am rewriting an application which has a requirement to obtain the name of an enum identifier from it's value, an operation called reflection in many languages. To my knowledge there is no native way to do this in plain old C.
The original applicaiton defined a reflection function for these particular enum values (approx. 90) which consists of a switch with a case for each value which returns a pointer to the identifier names. The case list was maintained manually when the enum definition changed. I initially wrote a simple sed script to generate the case statements from the header which defines the enum, but still had to copy/paste the result into the source file... not too bad once in a while but that will change frequently during the rewrite and will become a problem. So I have split out that enum definition into a separate header to ease parsing it, and written a simple script to generate another source file just for the reflection function which is invoked by the Makefile rules when the definition changes. This works well enough and allows the header to be included independently of the reflection source for those modules which do not require the reflection function, and can easily be reused for other enums and projects with minimal configuration, at the expense of the additional Makefile rules and proliferation of header files. The result is that this header (defs.h)... Code:
enum myenum { Code:
/* This source file generated from defs.h by ./make_defs_c.sh Mon May 22 17:30:57 MDT 2023 */ Code:
reflect: defs.c reflection.c A DDG search produces many hits for C++ and C-pound-sign, but nothing very useful for C. Have any of you good folks here at LQ had to do this and/or have any thoughts to share? Thanks in advance! |
yes, I think there is no native way.
I would create a list of values/names in a file (not c or h), and generate all the required c and h files based on that, in a makefile. |
You could also do something like this:
Code:
enum example { RED=0, GREEN, BLUE }; |
That can't be done directly, but the C preprocessor can turn symbol names into strings. This is useful for creating an array of symbol names and addresses.
Code:
struct ESTRUCT { |
Quote:
|
Quote:
May I ask why you would prefer to generate both from a third file? |
Quote:
And I agree, there seems no way of avoiding use of an external script to generate those declarations at compile time. I had hoped to find a clever and simple way of doing this all in the preprocessor but that now seems unrealistic. I was wrong - see clever, simple and elegant preprocessor only method provided by wainamoinen in post #11 below! A subtle complication of using an indexed array this way is that it introduces a restriction on those constant values in that they need to be zero based and contiguous or nearly so. It woulld be difficult to allow for constants with large offsets from zero, or for disjoint sub-ranges of constant values. Both of these are common and useful and the second, disjoint sub-ranges of constant values is important to my current use (the offset value in my example was intended to suggest this). This last point kept me focused on use of a switch, actually. Thanks! |
Quote:
Or did I completely miss your point (very possible!). But I appreciate the example and reminder of preprocessor quoting capability. Although aware of it, I don't think I have ever made use of it myself... food for thought. Thanks! |
Quote:
|
astrogeek - The address is for variables with storage. For an enum, you would use the value instead.
You still have to build the table and write code to look it up. :) Ed |
There is a native way, but requires the use of #defines. The method is called X Macro, not widely known.
Wikipedia has an article about it. The code is below. Note that the enum entries and the switch cases are "automatically" created. Code:
#include <stdio.h> Code:
$ ./a.out |
Quote:
The only initial drawback I see is that I would have to assign the value to each enum name and would lose the convenience of automatically generated sequential values. I may be able to adjust the ENUM_ENTRY macro to allow for that, or it may not be a problem that needs to be solved. I'll see what I can do with it and reply again, but thanks for the post, very helpful! |
If I include the '=' sign as part of the id and change the definition of ENUM_ENTRY as below...
Code:
#define ITEMS(I) \ This simple change to your example code... Code:
int main(void) Code:
./a.out Thanks, and take a bow! |
Yes, that's very clever and something I haven't seen before.
|
Anyways, if it changes so often, it should be handled run-time (read from file/DB).
|
All times are GMT -5. The time now is 10:58 AM. |