Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relax void * casting in C++

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?

like image 948
Matt Joiner Avatar asked Oct 03 '10 09:10

Matt Joiner


2 Answers

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++.

like image 58
Hasturkun Avatar answered Oct 25 '22 03:10

Hasturkun


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...

like image 23
Christoph Avatar answered Oct 25 '22 01:10

Christoph