Home > Enterprise >  Expansion of C preprocessor macros with integer arithmetic in a text file?
Expansion of C preprocessor macros with integer arithmetic in a text file?

Time:09-29

On my system, I have a /usr/include directory, with a curl/options.h file in it, which contains a preprocessor definition of CURLOT_FLAG_ALIAS.

If I have the following test.txt:

#include "curl/options.h"

curlot flag alias is: CURLOT_FLAG_ALIAS

Then I can do this to expand the macro in the text file:

$ gcc -E -P -x c -I/usr/include test.txt
typedef enum {
  CURLOT_LONG,
  CURLOT_VALUES,
  CURLOT_OFF_T,
  CURLOT_OBJECT,
  CURLOT_STRING,
  CURLOT_SLIST,
  CURLOT_CBPTR,
  CURLOT_BLOB,
  CURLOT_FUNCTION
} curl_easytype;
struct curl_easyoption {
  const char *name;
  CURLoption id;
  curl_easytype type;
  unsigned int flags;
};
CURL_EXTERN const struct curl_easyoption *
curl_easy_option_by_name(const char *name);
CURL_EXTERN const struct curl_easyoption *
curl_easy_option_by_id(CURLoption id);
CURL_EXTERN const struct curl_easyoption *
curl_easy_option_next(const struct curl_easyoption *prev);
curlot flag alias is: (1<<0)

However, this approach also dumped all the function definitions in curl/options.h; ultimately, to just process the text file, this gives a much "cleaner" result - have test.txt be just:

curlot flag alias is: CURLOT_FLAG_ALIAS

... and then use -imacros switch (and pipe into grep to remove empty lines):

$ gcc -E -P -x c -I/usr/include -imacros curl/options.h test.txt | grep -v '^[[:space:]]*$'
curlot flag alias is: (1<<0)

Great - except, I do not really want the (1<<0) in the text output - I want its expanded integer decimal value, 1; in other words, I'd want the text output to be:

curlot flag alias is: 1

I guess one way would be, to keep the original and modified text file, identify range of characters in the modified file of the parts that are changed from the original file, here (1<<0) - then feed that string into some calculator, then replace it with the output of the calculator. However, while (1<<0) is parseable by calculators like wcalc - I doubt many common idioms like (1u<<32) would be parseable by it, so even strings like these would have to go through the compiler I guess, and the C compiler is not REPL, so it cannot "just" give a value for an input like (1<<0) ...

Now, I'm aware the C preprocessor does not do arithmetic, apart from conditionals ( Can the C preprocessor perform integer arithmetic? ), so maybe what I want to achieve is impossible with C preprocessor (and possibly compiler) - if that is the case, are there any other tools to help me achieve replacement and expansion of C macros with integer arithmetic in a text file?

CodePudding user response:

One common approach is to actually compile and execute the code instead of merely preprocessing it. Have a file make_test.c containing:

#include <stdio.h>
#include "curl/options.h"

int main(void) {
    printf("curlot flag alias is: %d\n", CURLOT_FLAG_ALIAS);
    return 0;
}

and then have your build process compile and execute this program.

gcc -o make_test -I /usr/include make_test.c
./make_test

CodePudding user response:

Yes, you can extract the result of evaluating an integer constant expression using a system commonly referred to as preprocessor slots:

slot.h:

// slot.h
#define DIG DIG_CATe(DIG_2,DIG_1)
#define DIG_CATe(a,b) DIG_CAT(a,b)
#define DIG_CAT(a,b) a##b

#undef DIG_1
#if (SLOT) % 10 == 0
#define DIG_1 0
#elif (SLOT) % 10 == 1
#define DIG_1 1
#elif (SLOT) % 10 == 2
#define DIG_1 2
#elif (SLOT) % 10 == 3
#define DIG_1 3
#elif (SLOT) % 10 == 4
#define DIG_1 4
#elif (SLOT) % 10 == 5
#define DIG_1 5
#elif (SLOT) % 10 == 6
#define DIG_1 6
#elif (SLOT) % 10 == 7
#define DIG_1 7
#elif (SLOT) % 10 == 8
#define DIG_1 8
#elif (SLOT) % 10 == 9
#define DIG_1 9
#endif

#undef DIG_2
#if (SLOT/10) % 10 == 0
#define DIG_2 0
#elif (SLOT/10) % 10 == 1
#define DIG_2 1
#elif (SLOT/10) % 10 == 2
#define DIG_2 2
#elif (SLOT/10) % 10 == 3
#define DIG_2 3
#elif (SLOT/10) % 10 == 4
#define DIG_2 4
#elif (SLOT/10) % 10 == 5
#define DIG_2 5
#elif (SLOT/10) % 10 == 6
#define DIG_2 6
#elif (SLOT/10) % 10 == 7
#define DIG_2 7
#elif (SLOT/10) % 10 == 8
#define DIG_2 8
#elif (SLOT/10) % 10 == 9
#define DIG_2 9
#endif

// ...
#undef SLOT

test.c:

#define SLOT 2*5
#include "slot.h"
result 1: DIG
#define SLOT (1 3*4)*2
#include "slot.h"
result 2: DIG

output (cc -P -E):

result 1: 10
result 2: 26

Although the utility of using this for your problem is questionable.

  • Related