Question

I'm trying to build cairomm for gtkmm on windows using mingw. Compilation breaks at a function call which has a parameter which does a reinterpret_cast of a bool to a void*.

cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL);

This is where the code breaks, and reason is "invalid reinterpret_cast from bool to void*". Why is this happening, and how can I modify this line to get it to compile? Need help

Was it helpful?

Solution

I see this is user data and you have control over what is done with the value, cast the bool to an int first: reinterpret_cast<void *> (static_cast<int> (true)). Doing this makes sense in that the void* parameter takes the place of template functions in this ANSI-C library. All you need is a true/false value. So, there should be no danger in temporarily encoding this as a pointer as long as it is well documented as such. Really, you would be better off with this: reinterpret_cast<void *> (1) or reinterpret_cast<void *> (+true).

OTHER TIPS

It looks like it should work, according to the standard. Section 3.9.1-7 says bool is an integral type, and 5.2.10-5 says a value of integral type can be explicitly converted to a pointer using reinterpret_cast. It appears that your compiler is not fully standard.

Could you get away with changing the "true" to a 1? Converting between integers and pointer types is an old and dishonorable tradition in C and hence C++, and it would be surprising to find a compiler that wouldn't do it.

Or, if you really really have to do this, try (void *)true. Then wash your hands.

reinterpret_cast is a bad idea. Tell us more about the problem you're trying to solve, and perhaps we'll find a solution without resorting to reinterpret. Why do you want to convert bool to void*?

The only compiler I have that complains about this is GCC (MinGW with GCC 3.4.5) - and I'm not sure why. The standard seems to clearly indicate this is permitted:

3.9.1 Fundamental types

...

Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral types.

5.2.10 Reinterpret cast:

...

A value of integral type or enumeration type can be explicitly converted to a pointer.

That said, monjardin's workaround of using reinterpret_cast<void *> (static_cast<int> (true)) or reinterpret_cast<void *> (1) are reasonable workarounds.

It fails because the cast makes no sense - you are taking a boolean true/false value, and asking the compilre to interpret this as a pointer, which in blunt terms is a memory location. The two arent even remotely related.

Try a newer version of your compiler. I just tested and this cast works on at least gcc 4.1 and above. I don't know exactly how gcc versions map to mingw versions though.

In some situations, it is highly desirable to have the compiler warn or error on code like reinterpret_cast<void*>(true), even though this code is apparently legal C++. For example, it aids in porting to 64-bit platforms.

Casting a 64-bit pointer into an integral type that is smaller than a pointer (such as int or bool) is often a bug: you're truncating the pointer's value. Furthermore, the C++ specification doesn't seem to guarantee that you can directly cast a pointer into a smaller integral type (emphasis added):

5.2.10.4. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.

Likewise, casting a smaller integral type into a 64-bit pointer (as with reinterpret_cast<void*>(true)) is often a bug as well: the compiler has to fill in the pointer's upper bits with something; does it zero-fill or sign-extend? Unless you're writing low-level platform-specific code for memory mapped I/O access or DMA, you usually don't want to be doing this at all, unless you're doing something hacky (like stuffing a Boolean into a pointer). But the C++ specification doesn't seem to say much about this case other than that it is implementation-defined (footnote omitted):

5.2.10.5. A value of integral type or enumeration type can be explicitly converted to a pointer.*

A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.

@monjardin suggested reinterpret_cast<void*>(static_cast<int>(true)). If the origin of the error was the mismatch between the integral type's size and the pointer size, then this will work on most 32-bit platforms (where both int and void* are 32 bits) but fail on most 64-bit platforms (where int is 32 bits and void* is 64 bits). In that case, replacing int in this expression with a pointer-sized integer type such as uintptr_t or DWORD_PTR (on Windows) should work, since conversions between bool and pointer-sized integers are allowed, and so are conversions between pointer-sized integers and pointers.

Later versions of GCC have the following warning suppression options, but not for C++:

-Wno-int-to-pointer-cast (C and Objective-C only)
Suppress warnings from casts to pointer type of an integer of a different size.

-Wno-pointer-to-int-cast (C and Objective-C only)
Suppress warnings from casts from a pointer to an integer type of a different size.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top