1

I have a #define mapping an identifier (a function name) to a new name like this:

#define A doStuff

This part I cannot do anything about, I have to access "A" since the actual identifier (doStuff here) may change (and this is not under my control). Now the referenced symbol (doStuff) may or may not exist, and I want to invoke the function in the former case. For a plain function name I can test this easily:

#ifdef doStuff
    doStuff();
#endif

However, being restricted to the macro name, doing the same naively would be:

#ifdef A
    A();
#endif

which gives an error since the name "A" is defined, while "doStuff" is not. I'd like to check the existence of the name the macro resolves into, essentially:

#if defined(the-content-of-A)

but I cannot make it work.

So my question: is there any way to check whether an identifier represented by a macro is defined? If yes, how to do it? If no, is there a common pattern for a workaround?

Although I don't think that this is either C or C++ specific I'd like to note that I need something that works for an identifier defined "extern C" in C++. The solution must be platform independent.

Sorry if this was asked before, I could not find it, neither with google nor on SO.

tglas
  • 821
  • 6
  • 18
  • 2
    Please note that your example with `#ifdef doStuff` is wrong. You cannot detect presence of C/C++ functions at preprocessor level. Moreover, do you want to recognize `#define A` (i.e. `A` exists but has no value) or `#define A unavailable-function`? – dlask Jun 21 '15 at 07:54
  • If the target function doesn't exist, `A` should not be defined at all. Then you can detect the case with `#ifdef`. – user207421 Jun 21 '15 at 07:58
  • As many people answered, you can't change behavior due to function existence in the preprocessor. But you can do that with template meta-programming, see here http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence – Ophir Gvirtzer Jun 21 '15 at 08:15
  • Thanks for the clarificartion. It is well possible that the symbol which I called doStuff in the question in actually a macro in the real code. – tglas Jun 21 '15 at 08:28
  • All answers are to the spot, but I can accept only one. Thanks also to the others. – tglas Jun 21 '15 at 09:12

3 Answers3

2

Defining identifiers (functions, objects) is something that happens after the preprocessing, so you can not possibly determine during preprocessing whether a function will be defined later.

What you can do as workaround is that you always define a macro alongside with the function:

void A();
#define A_SUPPLIED

and then test against that:

#ifdef A_SUPPLIED
...
#endif
Ulrich Eckhardt
  • 15,392
  • 1
  • 25
  • 49
1

Well, no.

I think your real problem is that you don't understand the difference between macros (introduced to the preprocessor using #define and expanded using text substitution before the result is actually compiled in a later phase of compilation) and identifiers (which are compile time constructs that cannot be tested for by the preprocessor).

I say this because the only way

#ifdef doStuff
    doStuff();
#endif

will work as you claim is if doStuff() is a macro. It will not work if doStuff() is an identifier (for example, the name of a function or variable).

For example, in C++

#include <iostream>

void doStuff() {std::cout << "Hello\n";}

int main()
{
    #ifdef doStuff
        doStuff();
    #else
        std::cout << "Bye\n";
    #endif
}

will print Bye rather than Hello. That is because a function definition does not produce a macro, and is not detected by #ifdef.

About the only way is to define a macro as a companion to the function

 void DoStuff();
 #define DoStuff_DEFINED

 #ifdef DoStuff_Defined
     DoStuff();
 #else
     ComplainBitterly();     /*   assumes ComplainBitterly() exists of DoStuff_DEFINED is not defined */
 #endif
Peter
  • 32,539
  • 3
  • 27
  • 63
  • Thanks. It is well possible that the symbol which I called doStuff in the question in actually a macro in the real code. – tglas Jun 21 '15 at 08:28
  • If it is a macro, it can be tested for using the preprocessor. But it is not an identifier or a "symbol". – Peter Jun 21 '15 at 08:42
1

It's not possible to determine whether an identifier exists in pure C, with or without the macro (your #ifdef doStuff example doesn't actually work). This is because at macro expansion time, the compiler's just doing text substitution; it doesn't know what symbols are defined. The ideal approach would be for your library header to expose an A_IS_PRESENT macro or similar you can #ifdef off of here.

However, if that's not an option, it may be possible with platform-specific extensions. On Linux, for example, you can define a weak symbol, then determine whether it is overridden by the real deal:

#ifdef __cplusplus
extern "C" {
#endif
// Define a dummy function; if A is not present we will make A an alias of this
int A_surrogate() {}
#ifdef __cplusplus
}
#endif

// The alias attribute makes 'A' equivalent to 'A_surrogate'. The weak attribute
// means that if some other definition exists, that one takes precedence.
int __attribute__((weak, alias("A_surrogate"))) A();

int is_A_present() {
  // Was A in fact overridden?
  return &A != &A_surrogate;
}
bdonlan
  • 205,037
  • 27
  • 244
  • 316