8

I have a C program which has platform-specific defines for access to low-level hardware. On some platforms, two macros point to the same variable, on others they are different:

 //Platform_One.h
 #define FOO_PORT   (io.portA)
 #define BAR_PORT   (io.portB)

 //Platform_Two.h
 #define FOO_PORT   (io.portC)
 #define BAR_PORT   (io.portC)  //same

I have some initializer code that is different based on whether the #defines are the same or not. Conceptually, I'd like code like this:

 callback_struct_t callbacks[] = {
 #if FOO_PORT == BAR_PORT           //unfortunately invalid
     {&FOO_PORT, handle_foo_bar_func},
 #else
     {&FOO_PORT, handle_foo_func},
     {&BAR_PORT, handle_bar_func},
 #endif          
      {0,0}
 };

Is there a reliable way to test at compile time if two arbitrary macros have the same definition?

AstroCB
  • 12,337
  • 20
  • 57
  • 73
AShelly
  • 34,686
  • 15
  • 91
  • 152
  • Do the platforms not provide any other macro indicating what platform for which the code is being compiled? – Drew McGowen Jul 08 '14 at 14:08
  • can you `#define` a flag for platform two to indicate the ports are shared, and then test that flag when populating the `callbacks` array ? – Sander De Dycker Jul 08 '14 at 14:08
  • I'm trying to avoid adding extra code that has to be kept in sync with the other definitions. Using the platform indicator would require my code to be modified every time someone customizes their configuration. Both suggestions above are valid workarounds, but not as clean as I'd really like. – AShelly Jul 08 '14 at 14:22
  • 1
    I think you'll have to initialize the `callbacks` array by code (i.e., during runtime). In the case of a global variable - yes, that's an extra piece of code, but given the fact that it runs only once, it's not likely to impact the overall performance of your application. In the case of a local variable, the "initialization by code" will take place anyway, because the array has to retain its initial values every time the function is called. So even if you do have some "magical" way to do it with a macro, it's not going to make a significant difference (will save you an extra `if` at most). – barak manos Jul 08 '14 at 14:37
  • possible duplicate of http://stackoverflow.com/questions/2335888/how-to-compare-string-in-c-conditional-preprocessor-directives – cerkiewny Jul 08 '14 at 15:02
  • 1
    I don't see how the linked question is relevant. My #defines are not strings, they are variable names (or possibly their addresses). – AShelly Jul 08 '14 at 15:20
  • 1
    The possible duplicate is relevant to the extent that it describes comparing things other than pure (integer) numeric expressions in the C pre-processor — and to the extent it has the same answer: No, you can't do it. The C preprocessor is an interesting tool, but it has limitations, and you are seeking to go beyond those limitations. – Jonathan Leffler Jul 08 '14 at 15:32

3 Answers3

5

You cannot compare the preprocessor macros as strings. One possibility would be to put the hardware port address (e.g., via another macro in the platform-specific headers) into the #defines and then compare the addresses.

However, the easiest way might be to do the comparison of addresses in actual code, e.g.:

if (&FOO_PORT == &BAR_PORT) {
    // populate callbacks with handle_foo_bar_func
} else {
    // populate callbacks with handle_foo_func and handle_bar_func
}

While not done in pre-processor, the compiler may be able to optimise away the unused branch since the hardware addresses are likely compile-time constants.

Arkku
  • 41,011
  • 10
  • 62
  • 84
2

With the gnu c processor it can be done with stringification: https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification

You could do something like this:

#include <stdio.h>
#include <string.h>

#define FOO_PORT   (io.portA)
#define BAR_PORT   (io.portB)

//#define FOO_PORT   (io.portC)
//#define BAR_PORT   (io.portC)

#define XMACRO_TEST(macro_a, macro_b) MACRO_TEST(macro_a, macro_b)

#define MACRO_TEST(macro_a, macro_b) \
    if(strcmp((#macro_a),(#macro_b)) == 0) { \
        printf(#macro_a" == "#macro_b"\n"); \
    } else { \
        printf(#macro_a" != "#macro_b"\n"); \
    } \

int main(int argc, char *argv[])
{
    XMACRO_TEST(FOO_PORT, BAR_PORT)

    return 0;
}
Optokopper
  • 203
  • 1
  • 5
  • Neat, but that's not exactly what he wants: he wants a compile-time conditional `#IF` not a code `if`, and unfortunately it's for structure initialisation so you can't use `if` and rely on one branch being compiled out. – Rup Jul 09 '14 at 09:27
1

You can compare macros that evaluate to integers. My understanding is you have three options:

  • change the macro logic
  • use numerical values for port number macros (are they physical addresses?)
  • fill the callback structure with c code as one of the comments suggets.

The last option seems to be the most favourable. With propper use of const, the calculation will be carried at complile time by most compilers, anyway.

Jakub
  • 583
  • 3
  • 8