1

I have to maintain C code that has both generic components and product specific components. I would like to simplify my code so that I have just one generic product.h file which has a structure like

#if (PRODUCT_ID == 1)
    #define PRODUCT_NAME Product1
#else
    #if (PRODUCT_ID == 2)
        #define PRODUCT_NAME Product2
    #else
        #error "Unsupported product id"
    #endif
#endif

Then, whenever I have a header foo.h which has product specific components, I would like to use syntax like this

#include "product.h"
#include PRODUCT_SPECIFIC_INCLUDE

where PRODUCT_SPECIFIC_INCLUDE should be derived from __FILE__ and PRODUCT_NAME macro in such a way that it would translate to

#include "Product1/foo.h"

that is, the product specific header file has the same filename as the generic file, but is located in a product specific folder, whose name is the value of PRODUCT_NAME macro.

It seems that whatever I try has preprocessor stringification issues. I can't be the first to want such a structure. What am I missing?

Update

Here is what I currently have for PRODUCT_SPECIFIC_INCLUDE which does not work

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define PRODUCT_SPECIFIC_INCLUDE TOKENPASTE2(PRODUCT_SPECIFIC, __FILE__)
5
  • I'm not sure it's possible to do with the standard C preprocessor. You might have to do it in the build environment instead. Commented Jan 20, 2017 at 14:58
  • Please show the macro related to PRODUCT_SPECIFIC_INCLUDE Commented Jan 20, 2017 at 15:07
  • Here is what I currently have for PRODUCT_SPECIFIC_INCLUDE which does not work <code>#define TOKENPASTE(x, y) x ## y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) #define PRODUCT_SPECIFIC_INCLUDE TOKENPASTE2(PRODUCT_SPECIFIC, __FILE__)</code> Commented Jan 20, 2017 at 15:10
  • It would be better to add it to the question body as it is the important part. Commented Jan 20, 2017 at 15:18
  • This may be a duplicate of stackoverflow.com/questions/5873722/c-macro-dynamic-include Commented Jan 20, 2017 at 16:27

2 Answers 2

2

You can do something like

#define STR2(F) #F
#define STR(F) STR2(F)
#define MAKE_PRODUCT_INCLUDE(FILE) STR(PRODUCT_SPECIFIC/FILE)

#include MAKE_PRODUCT_INCLUDE(foo.h)

but I don't know a way to avoid repeating the file name. Using __FILE__ gives a string and there is no way that I know to concatenate strings in the preprocessor (the fact that juxtaposed strings are concatenated is a parser feature, and ## is not usable for that "foo""bar" is not the spelling of a valid token).

0

The first code could be reduced to:

#if (PRODUCT_ID == 1)
    #define PRODUCT_NAME Product1
#elif (PRODUCT_ID == 2)
    #define PRODUCT_NAME Product2
#else
    #error "Unsupported product id"
#endif

Secondly, you are trying to get the required include header name but the problem is in these two lines:

#define TOKENPASTE(x, y) x ## y
#define PRODUCT_SPECIFIC_INCLUDE TOKENPASTE2(PRODUCT_SPECIFIC, __FILE__)

__FILE__ : This macro expands to the name of the current input file, in the form of a C string constant

TOKENPASTE(PRODUCT_SPECIFIC, __FILE__) |--> product ## "foo.h"

product and " can never give a valid token. And that's why the CPP gives you error. What you need is writing the filename as plaintext so you can combine it with other macros.

You can do it like this:

#define TOKENPASTE(x) #x
#define TOKENPASTE2(x) TOKENPASTE(x)
#define PRODUCT_SPECIFIC_INCLUDE TOKENPASTE2(PRODUCT_SPECIFIC/foo.h)
#include PRODUCT_SPECIFIC_INCLUDE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.