ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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.
But I have wondered how others approach this problem with plain old 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?
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.
Should be easy to auto generate the two declarations, but it's going to be beyond CPP, so you're going to have to use some sort of external tool, whether that be shell-script, awk, or even venerable old 'm4'.
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 {
const char *name;
void *ptr;
};
#define EXAMPLE(x) {#x, &x}
ESTRUCT mytable[] = {
EXAMPLE (var1),
EXAMPLE (var2),
EXAMPLE (var3)
};
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.
I seem to recall seeing a technique similar to this, but with two sets of definitions for the macros where one of them creates the enum { ... } definition, and the other produces the string table.
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.
My reason for generating the c-source from the header file itself was that it seemed it would be more readable/meaningful for myself to maintain the list in native C enum declaration syntax.
May I ask why you would prefer to generate both from a third file?
Should be easy to auto generate the two declarations, but it's going to be beyond CPP, so you're going to have to use some sort of external tool, whether that be shell-script, awk, or even venerable old 'm4'.
Mapping the constant values to names via an indexed array is the most straight forward way to provide runtime storage and access. I like the parameterized #define as a convenient way of referencing them.
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.
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 {
const char *name;
void *ptr;
};
#define EXAMPLE(x) {#x, &x}
ESTRUCT mytable[] = {
EXAMPLE (var1),
EXAMPLE (var2),
EXAMPLE (var3)
};
Ed
Enum constants are evaluated and replaced by the preprocessor and have no runtime storage of their own, so I am confused by your example. Assuming the x parameter is intended to be the enum identifier name you cannot take its address.
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.
My reason for generating the c-source from the header file itself was that it seemed it would be more readable/meaningful for myself to maintain the list in native C enum declaration syntax.
May I ask why you would prefer to generate both from a third file?
Code written in c is not really suitable for this (although not impossible). A simple text file can be parsed easily and generate include and source files together. It's like idl (but much simpler).
I had prepared a reply to the previous posts to wrap this thread up, but your post has stopped the presses! I had decided the switch was the way to go and this looks like it might be the way to do it without an external script - thanks!
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!
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.