3

Say I have some C code like:

#define FOO 2
#define BAR 3
#define BAZ 500

void get_value(int val) {
  printf("The value is %s\n", some_function_or_macro_or_something(val));
}

int main(int argc, char** argv) {
  get_value(BAZ);
  get_value(FOO);
  return 0;
}

and I want it to print out "The value is BAZ" and "The value is FOO". But there are thousands of #defines, so I want to do it programmatically.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 4
    Are you programming in C or C++. The answers may depend on the language. The C language is different than C++. – Thomas Matthews Jan 22 '15 at 20:27
  • 1
    This seems to answer your problem : http://stackoverflow.com/questions/11693219/macro-expansion-and-stringification-how-to-get-the-macro-name-not-its-value-s – da_m_n Jan 22 '15 at 20:41
  • It is C code. I put it in the title and the first sentence, but I probably shouldn't have tagged it C++. – cuppacoffee Jan 22 '15 at 21:02
  • You don't explain what are your "thousands of macros"... Please edit your question to improve it... (and give some more realistic, more relevant, more motivating, code samples); also give some real context – Basile Starynkevitch Jan 22 '15 at 22:06
  • @BasileStarynkevitch I want to do this at run time. So say my program gets inputs from several different sources over the network, I want to debug what is passed to the program by printing out what is received. Right now I can print the hex value, but I would rather print the string of the macro name. – cuppacoffee Jan 22 '15 at 22:37
  • You don't motivate your question (you really should *edit your question* to improve it). How large is your code base? Perhaps you want some automatic instrumentation or some aspect oriented programming? What compiler and system are you using? If using a recent [GCC](http://gcc.gnu.org/) on Linux you might consider customizing it with [MELT](http://gcc-melt.org/) but that could take you a week of work. – Basile Starynkevitch Jan 23 '15 at 07:02
  • Show a dozen of the *exact* `#define` you have (so *edit your question* to improve it). Maybe you could parse them with `awk` – Basile Starynkevitch Jan 23 '15 at 07:06
  • So you actually want to map back **from macro value** to **macro identifier**, as in "given the value 500, how do I arrive at the string `BAZ`"? – Jens Jan 23 '15 at 09:44
  • Can you wrap the `get_value()` call inside another macro? – Masked Man Jan 23 '15 at 10:16
  • @Happy yes, sure, there is no restriction. – cuppacoffee Jan 23 '15 at 18:01
  • Alright, I have edited my program to provide this mapping. – Jens Jan 23 '15 at 19:53

4 Answers4

3

C is definitely capable of doing this using # stringizing operator, but you need to call macro with identifier directly:

#include <stdio.h>

#define FOO 2
#define BAR 3
#define BAZ 500

#define get_value(val)     \
  printf("The value is %s\n", #val);

int main(void)
{
  get_value(BAZ);
  get_value(FOO);

  return 0;
}

In your example after passing value of e.g. BAZ to get_value function, the token BAZ is not recognized anymore, as arguments are passed by value. In other words macro identifier is gone (of course you can still stringize its replacement, see comment below).

What can I do more?

Here is some small hack to obey this "top-level" rule. Assuming that you have small amount of object-like macros (constants) with unique values, then you can do something like:

#include <stdio.h>

#define FOO 2
#define BAR 3
#define BAZ 500

#define STRINGIFY(val) #val

void get_value(int val) {
  switch (val) {
    case FOO :
      printf("The value is %s\n", STRINGIFY(FOO)); break;
    case BAR :
      printf("The value is %s\n", STRINGIFY(BAR)); break;
    case BAZ :
      printf("The value is %s\n", STRINGIFY(BAZ)); break;
  }
}

int main(int argc, char* argv) {
  get_value(BAZ);
  get_value(FOO);
  return 0;
}

Result:

The value is BAZ
The value is FOO
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • 1
    It is possible to stringize the result of macro expansion as well, i.e. you can get "500" for BAZ if you want. – Nick Zavaritsky Jan 22 '15 at 20:42
  • Thank you for such a well developed response, but like I said, I have thousands of defines, and a switch statement would be just too cumbersome. – cuppacoffee Jan 22 '15 at 21:04
0

Use the right tool for the job. Which tool knows all about macros? A compiler. GNU gcc and clang both allow to dump the list of defined macros:

$ cc -E -dM -x c /usr/include/stdio.h
#define BUFSIZ 1024
#define EOF (-1)
#define FILENAME_MAX 1024
#define FOPEN_MAX 20
#define L_ctermid 1024
#define L_cuserid 17
#define L_tmpnam 1024
#define NULL ((void *)0)
#define P_tmpdir "/tmp/"
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
/* etc */

will list the whole shebang defined by <stdio.h> and everything it includes. If you need to process this data programmatically in a C program,

#include <stdio.h>

#define BIG_ENOUGH   1024

int main (void)
{
    char buffer[BIG_ENOUGH];
    FILE *fp = popen ("cc -E -dM -x c /usr/include/stdio.h", "r");
    while (fgets(buffer, sizeof buffer, fp) != NULL) {
       char identifier[BIG_ENOUGH];
       int value;
       if (sscanf (buffer, "#define %s %d", identifier, &value) == 2) {
           printf ("value %d is from macro %s\n", value, identifier);
       }
    }
    fclose(fp);
    return 0;
}

This prints here for stdio.h

value 1024 is from macro BUFSIZ
value 1024 is from macro FILENAME_MAX
value 20 is from macro FOPEN_MAX
value 1024 is from macro L_ctermid
value 17 is from macro L_cuserid
value 1024 is from macro L_tmpnam
value 1 is from macro SEEK_CUR
value 2 is from macro SEEK_END
value 0 is from macro SEEK_SET
value 308915776 is from macro TMP_MAX
[...]

Instead of stdio.h you simply use your file.c as input.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • I want to do this at run time. So say my program gets inputs from several different sources over the network, I want to debug what is passed to the program by printing out what is received. Right now I can print the hex value, but I would rather print the string of the macro name. – cuppacoffee Jan 22 '15 at 22:36
  • @cuppacoffee Then I suggest: 1) Save what you receive over the network in a file. 2) process that file as shown. 3) The macro name is the part after the #define up to the next space (may include arguments for function-like macros). 4) The replacement text everything that follows. This approach *beats any parsing you may do yourself* because the compiler does it already for you. Think of backslash/newline line continuation. This is all resolved for free. – Jens Jan 23 '15 at 06:25
0

The classical, if somewhat heavyweight, approach is a table file:

enum.tab:

#ifndef DECL_CONST
#    define DECL_CONST(name, value)
#endif

DECL_CONST(FOO, 2)
DECL_CONST(BAR, 3)
DECL_CONST(BAZ, 500)
#undef DECL_CONST

enum.h:

enum My_Enum
{
#define DECL_CONST(name, value) name = value,
#include "enum.tab"
};

char const* get_name(enum My_Enum value);

enum.c:

#include "enum.h"

char const* get_name(enum My_Enum value)
{
    switch (value)
    {
    #define STR(name) #name
    #define DECL_CONST(name, value) case value: return STR(name);
    #include "enum.tab"
    default:
        return 0;
    }
}

main.c:

#include "enum.h"

void process_value(int v)
{
    char const* s = get_name((enum My_Enum) v);
    if (s)
        printf("The name of value %d is %s\n", v, s);
    else
        printf("There is no name for value %d\n", v);
}

int main()
{
    process_value(1);
    process_value(2);
    process_value(3);
    process_value(500);
    process_value(501);
    return 0;
}

Of course, you can expand this basic scheme to include as many attributes as you like and support any number of dependencies between them. Note that if you have more than one name defined to the same value, the compilation of switch statement will fail.

ach
  • 2,314
  • 1
  • 13
  • 23
-1

Not sure it is possible. GCC states in their manual :

There is no way to convert a macro argument into a character constant.

da_m_n
  • 821
  • 7
  • 10