-2

I read a piece of header code and I found below:

ObjPtr.h:

#include <dlfcn.h>

#define OBJPTR(X)        void* X##Ptr ;         \
                            void* (*X##ObjPtr)() ;

void * CreateObj(void * handler, char* LibName, char* FunctionName);

Transaction.c

//...
OBJPTR(DB);
//...
DBObjPtr = CreateObj(DBPtr, "DBTransaction", "Function1");
if ((unsigned long)(DBObjPtr)(csPara1, csPara2) != PD_FOUND)
{
    //...

First, I don't understand what does it mean in the define line in the header file. (Why there is X## in the define line? What does it mean?)

Second, in the c file object is created instead of calling function directly. I think the purpose of such design is for isolation between objects for ease in maintenance and solution build/delivery; or code encryption from different developers, if I am correct. But what else? Or what kind of this design pattern?

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
EthanAlef
  • 35
  • 6
  • 1
    Also related: https://stackoverflow.com/questions/18031280/whats-the-meaning-of-in-a-c-macro , https://stackoverflow.com/questions/216875/what-are-the-applications-of-the-preprocessor-operator-and-gotchas-to-conside – Killzone Kid May 28 '18 at 10:14
  • This does not appear to be a C++ question. – Max Langhof May 28 '18 at 11:06
  • @MaxLanghof - actually it is, since the answer is essentially the same in both C and C++. In any event, marked as a dup of another question (which is tagged both C and C++, and also a dup of other questions). – Peter May 28 '18 at 11:21

1 Answers1

1

## is the preprocessor's (!) concatenation. In the given case, using the macro creates two variables:

OBJPTR(DB);

Will be resolved to:

void* DBPtr;
void* (*DBObjPtr)();

Actually, what we find here is no valid C++ (which is what you tagged the question):

  1. void* (*DBObjPtr)() declares a function pointer accepting no arguments, but it is later called with two of them.
  2. The function declared returns pointer to void, but it is assigned without any cast to a function pointer.

This code only is valid in C (void* (*DBObjPtr)() declares a function pointer with argument list left undefined; no-argument-function requires explicit void as argument: void* (*x)(void)!), and C allows implicit cast from pointer to void to other pointer types.

Intention is probably providing some kind of polymorphism in C:

DBObjPtr = CreateObj
(
    // probably used as some kind of handle; as not being passed
    // as pointer to pointer, the function cannot re-assign, but
    // only use it; so I assume that is has been initialized at
    // some point before this function call...
    DBPtr,
    // some kind of identifier from where to load a function from for
    // later use; as the parameter is called "library", it might load
    // the address of a function within a SO (*nix) or DLL (windows)
    "DBTransaction",
    // the name of the function to load
    "Function1"
);

In C++, you'd probably handle it differently:

class Loader;

Loader* db = createLoader(); // initialization lacking in your sample code;
                             // alternatively (and probably better!) via constructor
void* (*fptr)(int, int) = db->createObj("L", "F");

This won't work yet work, we need to apply some changes yet. First, we need to change the return type of the function, it must return a function pointer accepting arbitrary arguments. You can let it return either arbitrary arguments (via an ellipsis) or just have an empty argument list - does not matter, you will have to cast the result anyway (unless if using second variant and the function loaded really does not take any arguments...). But since C++11, there is a more elegant way to do the stuff, the function could be implemented as a variadic template function:

class Loader
{
public:
    template <typename ... TT>
    auto createObj(char const*, char const*) -> void*(*)(TT ...);
};

The cast then would be hidden away within the function, and you could simply use it as:

auto f = loader->createObj<int, int>("L", "F");
// ^ yeah, let's profit from C++11 again...

Just for if you are curious: The pre-C++11 way:

class Loader
{
public:
    void* (*createObj())(...);
    // function returning function pointer - ugly syntax, I know
    // (a typedef for the function pointer makes reading a little easier...)
};

void*(*f)(int, int) = reinterpret_cast<void*(*)(int, int)>(create());

One last note to the original macro: I personally would not use it, not even in C! It might appear nice for the lazy ones, but actually just obfuscates the declaration of variables and and additionally produces less type-safe function pointers. So I would have declared the variables myself:

void* db /*= ...*/ ;
void* (*f)(int, int) = createObj(db, "L", "F");
//         ^    ^    already with correct parameter list
Aconcagua
  • 24,880
  • 4
  • 34
  • 59