2

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*?

Community
  • 1
  • 1

2 Answers2

2

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);
Mark Nunberg
  • 3,551
  • 15
  • 18
  • I agree with you but my use case is wrapping a C library so i cannot use class in my public header file (and that's the reason of using void*) – Filippo Cucchetto Mar 28 '16 at 18:41
  • You can still make a dummy struct when running under C, for example: `#ifndef __cplusplus typedef struct IndexCDummy Index`. I've used this approach in the past - it ensures user type safety. `IndexCDummy` in this case isn't ever defined anywhere, but it does make the compiler aware of this typed opaque pointer. I'd put this in my answer, but it would make the answer substantially different from the way it stands – Mark Nunberg Mar 28 '16 at 18:56
0

Creating a typedef for void is a bit awkward. More common practice is to define void* as IndexHandle and force clients of your code to read or pass as a parameter a value of the opaque handle type. All casting should take place inside of your code.

jszpilewski
  • 1,632
  • 1
  • 21
  • 19