djs
djs

Reputation: 4776

How can I generate a list of #define values from C code?

I have code that has a lot of complicated #define error codes that are not easy to decode since they are nested through several levels.

Is there any elegant way I can get a list of #defines with their final numerical values (or whatever else they may be)?

As an example:

<header1.h>
#define CREATE_ERROR_CODE(class, sc, code) ((class << 16) & (sc << 8) & code)
#define EMI_MAX 16

<header2.h>
#define MI_1 EMI_MAX

<header3.h>
#define MODULE_ERROR_CLASS MI_1
#define MODULE_ERROR_SUBCLASS 1
#define ERROR_FOO CREATE_ERROR_CODE(MODULE_ERROR_CLASS, MODULE_ERROR_SUBCLASS, 1)

I would have a large number of similar #defines matching ERROR_[\w_]+ that I'd like to enumerate so that I always have a current list of error codes that the program can output. I need the numerical value because that's all the program will print out (and no, it's not an option to print out a string instead).

Suggestions for gcc or any other compiler would be helpful.

Upvotes: 5

Views: 7040

Answers (6)

user562374
user562374

Reputation: 3897

Is there any elegant way I can get a list of #defines with their final numerical values

For various levels of elegance, sort of.

#!/bin/bash

file="mount.c";
for macro in $(grep -Po '(?<=#define)\s+(\S+)' "$file"); do
    echo -en "$macro: ";
    echo -en '#include "'"$file"'"\n'"$macro\n" | \
    cpp -E -P -x c ${CPPFLAGS} - | tail -n1;
done;

Not foolproof (#define \ \n macro(x) ... would not be caught - but no style I've seen does that).

Upvotes: 1

AShelly
AShelly

Reputation: 35540

I think the solution is a combo of @nmichaels and @aschepler's answers.

Use gcc's -dM option to get a list of the macros. Use perl or awk or whatever to create 2 files from this list:

1) Macros.h, containing just the #defines.

2) Codes.c, which contains

#include "Macros.h"

ERROR_FOO = "ERROR_FOO"
ERROR_BAR = "ERROR_BAR"

(i.e: extract each #define ERROR_x into a line with the macro and a string.

now run gcc -E Codes.c. That should create a file with all the macros expanded. The output should look something like

1 = "ERROR_FOO"
2 = "ERROR_BAR"

I don't have gcc handy, so haven't tested this...

Upvotes: 4

user541686
user541686

Reputation: 210445

Here's a little creative solution:

Write a program to match all of your identifiers with a regular expression (like \#define :b+(?<NAME>[0-9_A-Za-z]+):b+(?<VALUE>[^(].+)$ in .NET), then have it create another C file with just the names matched:

void main() {
    /*my_define_1*/ my_define_1;
    /*my_define_2*/ my_define_2;
    //...
}

Then pre-process your file using the /C /P option (for VC++), and you should get all of those replaced with the values. Then use another regex to swap things around, and put the comments before the values in #define format -- now you have the list of #define's!

(You can do something similar with GCC.)

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753725

The program 'coan' looks like the tool you are after. It has the 'defs' sub-command, which is described as:

defs [OPTION...] [file...] [directory...]

Select #define and #undef directives from the input files in accordance with the options and report them on the standard output in accordance with the options.

See the cited URL for more information about the options. Obtain the code here.

Upvotes: 2

aschepler
aschepler

Reputation: 72311

If you have a complete list of the macros you want to see, and all are numeric, you can compile and run a short program just for this purpose:

#include <header3.h>
#include <stdio.h>

#define SHOW(x) printf(#x " = %lld\n", (long long int) x)

int main(void) {
    SHOW(ERROR_FOO);
    /*...*/
    return 0;
}

As @nmichaels mentioned, gcc's -d flags may help get that list of macros to show.

Upvotes: 1

nmichaels
nmichaels

Reputation: 50941

GCC's -dM preprocessor option might get you what you want.

Upvotes: 7

Related Questions