简体   繁体   中英

C/C++ aliasing functions to other function with different arguments

The following is some background as to what I want to do and why. The actual question is at the very bottom...

I have an API that has some format. For instance

int f(void *str1, void *str2) {...}

I want to reimplement the system behind the API so that it can be a drop in replacement for the old system. However it turns out that str1 is now unnecessary and moreover doesn't make sense to have if you're aware that you're using my new system. Therefore, I want to be able to expose the underlying API that makes sense:

int f_internal(void *str2);

Right now I have code that looks like this:

#ifdef  USE_INTERNAL
#define INTERNAL(sym) sym##_internal
#else
#define INTERNAL(sym) sym
#endif

extern "C" {
#ifndef USE_INTERNAL
int f(void *str1, void *str2){
  return INTERNAL(f)(str2);
}
#endif

SOME_ATTRIBUTES
int
INTERNAL(f)(void *str2){
  ... // actual content
} EXPORT_FUNCTION_MACRO(INTERNAL(f), 1);

}

The effect is if I define USE_INTERNAL , a call to f(a) works, but I don't define it then we have to use the f(a, b).

The problem I am encountering is that EXPORT_FUNCTION_MACRO itself defines another function name but doesn't evaluate INTERNAL(F) first. This results in the message

dir: error: pasting ")" and "_" does not give a valid preprocessing token
       INTERNAL(sym) \
--- NOTE--- EXPORT_FUNCTION_MACRO takes args 'sys' and 'n'
other_dir: note: in definition of macro ‘EXPORT_FUNCTION_MACRO’
   void _example##sym##_##n(void) {} \

WHAT I WANT TO DO:

I want to have a compile flag that can change the number of arguments needed to call something. Maybe something like (if it existed)

using f(a, b) = f_internal(a);

Any ideas?

This results in the message

To fix the message let macro arguments expand before concatenating them.

#define EXPORT_FUNCTION_MACRO_X(sys, n) EXPORT_FUNCTION_MACRO(sys, n)
EXPORT_FUNCTION_MACRO_X(INTERNAL(f), 1);

You could achieve that with a macro in the C part:

#define f(...) CONCAT(f, NUM(__VA_ARGS__, 2, 1)) (__VA_ARGS__)
#define CONCAT(X, Y) CC(X, Y)
#define CC(X, Y) X ## Y
#define NUM(X, Y, N, ...) N

#ifdef __cplusplus
extern "C"
#endif
void f_internal(void* str);

// specifically compiled for C or C++ anyway (and most likely inlined)
// -> no need for extern "C" for these:
void f1(void* str) { f_internal(str); }
void f2(void* unused, void* str) { f_internal(str); }

The macro f would select the correct function out of f1 and f2 , which again would call f_internal with the correct argument. Works for both C and C++. If you prefer, you could still just provide two overloads for C++ separately and let only the C people deal with the macros.

I doubt one could call that 'elegant'; if you want to qualify as 'ugly' – up to you. But at least it works...

The following code behaves like this:

  • If USE_INTERNAL is defined, defines an inline (c++) / static (c) function int f(void* str) .

  • Otherwise, defines an inline (c++) / static (c) function int f(void* str1, void* str2) .

Both functions are trampolines to the actual ( int f_internal(void* str) ) function.

Note that since the functions are defined in the header, inline (c++) / static (c) is required to keep them from violating the ODR rule (I am a c++ person, so I don't know any way better than static to achieve this in c. If there is, please let me know).

#ifdef __cplusplus
extern "C"
#endif
int f_internal(void* str);

#ifdef USE_INTERNAL

#ifdef __cplusplus
inline
#else
static
#endif
int f(void* str1, void* str2) {
    return f_internal(str2);
}

#else

#ifdef __cplusplus
inline
#else
static
#endif
int f(void* str) {
    return f_internal(str);
}

#endif

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM