Reputation: 118590
In C, it's not an error to cast pointers to and from void *
.
A major obstacle in porting to C++ is the need to cast pointers when returning from functions dealing with generic pointers such as malloc
, and functions declared in my own code such as void *block_get(Blkno const blkno);
.
My code however is intended to be compiled by C and C++ compilers successfully. If I provide explicit casts everywhere for the sake of C++, they must be C-style casts and I may be masking bugs due to casting non-pointer types to and from pointer types from both languages.
My reference error is the following:
struct Cpfs *cpfs = calloc(1, sizeof(*cpfs));
which in MSVC produces:
Error 2 error C2440: 'initializing' : cannot convert from 'void *' to 'Cpfs *' e:\src\cpfs\cpfs.c 179
Evidently I can't use new
or static_cast
which I'd naturally use if I was no longer using C. What's the best way to provide maximum type safety surrounding void *
for each language with minimal verbosity?
Upvotes: 6
Views: 2236
Reputation: 36412
I'd suggest either simply using C style casts, or wrapping the cast in a macro that either expands to nothing (in C), or a static_cast
in C++.
Upvotes: 5
Reputation: 169683
If your compiler supports decltype()
, you can use some macro magic to avoid having to explicitly repeat the type name (and, thanks to sizeof
, the element size):
#ifdef __cplusplus
#define my_calloc(VAR, COUNT) \
static_cast<decltype(VAR)>(std::calloc(COUNT, sizeof *VAR))
#else
#define my_calloc(VAR, COUNT) calloc(COUNT, sizeof *VAR)
#endif
Example usage:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
struct Cpfs *cpfs = my_calloc(cpfs, 42);
The cleaner solution would probably be to just use a C compiler and link the object files, though...
Upvotes: 2
Reputation: 36046
make a replacement allocator function that you can define differently for C and C++ builds :- Something like this in a header file:
#ifdef __cplusplus
template<typename TypeT>
TypeT* MyAlloc(TypeT** pOut,size_t cb){
*pOut = static_cast<TypeT*>(malloc(cb)); //aint c++ pretty.
return *pOut;
}
#else
extern void* MyAlloc(void** ppv, size_t cb);
#endif
Now you have, in c++ builds, a function that can infer the type of thing its dealing with, and in C builds, its a regular function that returns a void*.
The only problem is the need to pass in the pointer to allocate - the c++ compiler wont try to deduce a template parameter based only on the return type of a function afaik. So you could call it agnostically like this :-
int *p;
if(MyAlloc(&p,sizeof(int)*n)){
...
Upvotes: 1
Reputation: 3360
Maybe something like this? (untested, no compiler available, not using macros very often):
#ifdef __cplusplus
#define pointer_cast(type, pointer) reinterpret_cast<type>(pointer)
#else
#define pointer_cast(type, pointer) (type)(pointer)
#endif
Upvotes: 0
Reputation: 4869
The only solution I know is to do explicit casting:
struct Cpfs *cpfs = (Cpfs*)calloc(1, sizeof(*cpfs));
Here both compilers are satisfied. Also that remember, that for older compilers malloc may return char*.
hth
Mario
Upvotes: 0