Search code examples
c++ccastingundefined-behaviorvoid-pointers

Casting to void* and typedefs in C++


I'm wrapping a C++ library by writing a C interface. For this reason i created a C header file where most of the functions return/accept void* instead of C++ class pointers.

I know that is dangerous to cast from/to void* in C++, see Casting to void* and Back to Original_Data_Type*

Currently with inheritance i'm always casting to the base class of an object before assigning to void*

void* temp = static_cast<BaseClass*>(ptr)

and back

BaseClass* base = static_cast<BaseClass*>(voidPtr)
DerivedClass* derived = dynamic_cast<DerivedClass*>(base)

However using void* in a header files remove semantics and make complex functions hard to read. For example:

void myComplexFunc(void* index, void* data, void* somethingElse)

For mitigating this i wanted to use typedefs that even if they don't give any type safety at least they give to reader some insights. Compare the previous snippet with this one

extern "C" 
{
...
typedef void Index;
typedef void DBRecord;
typedef void DBResult;
void myComplexFunc(Index* index, DBRecord* data, DBResult* somethingElse)
...
}

Basically these typedefs act as a sort for documentation when multiple void* are used as parameters of a function (Keep in mind that i'm wrapping multiple C++ classes each with 10 methods, so there're lots of functions that thake a void* as first parameter).

For this reason i wanted to use to typedefs

extern "C" // In.h file (declaration)
{
typedef void Index;
...
Index* getIndex();
void modifyIndex(Index* index);
...
// In .cpp file (definition)
Index* getIndex() {
  DerivedCppIndex* derived = ...
  BaseCppIndex* base = static_cast<BaseCppIndex*>(derived)
  return base;
}
...
void modifyIndex(Index* index) {
  BaseCppIndex* base = static_cast<BaseCppIndex*>(index);
  DerivedCppIndex* derived = dynamic_cast<DerivedCppIndex*>(base);
  ...
}

Does the use of a typedef instead of void* causes any trouble regarding the issues of assignment to void*?


Solution

  • It shouldn't cause any trouble, but it will only give API users a false sense of security (as any arbitrary pointer will also work). There's nothing to prevent the compiler from complaining if you do something like:

    int i;
    // ....
    modifyIndex(&i);
    

    So while you won't have any problems, you won't have any compile-time checks and enforcements either.

    Do note that you have the choice of simply declaring the class without actually defining it.

    The proper way to solve the void-pointer "problem" (and it's not really a problem, it's just an aspect of C (and thus C++) which may make code difficult to maintain without proper care/documentation) is to somehow expose Index as an opaque type; e.g.

    // index.h
    class Index;
    // ...
    void modifyIndex(Index *i);