views:

1104

answers:

7

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

+12  A: 

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

Judge Maygarden
reinterpret_cast<void *> (static_cast<int> (true))Thanks. This did the trick, and I've been looking for explanations about casting, but couldn't find anything nice. Can you point me to a page that explains casts well?
Sahasranaman MS
wanna make it look cute? try reinterpret_cast<void*>(+ true) :P
Johannes Schaub - litb
Michael Burr
A: 

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.

Visage
+1  A: 

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

I think he is using a library that stores user data as void*. There is nothing he can do. This is actually a very common way of storing tag data in libraries.
Coincoin
argh, yea I agree... I still steer clear from reinterpret_cast when I can
Passing a pointer to the user data (i.e. a pointer to a bool) would avoid the nonsensical typecast. (However, it would also require keeping track of the user data's lifetime.)
bk1e
A: 

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.

Greg Rogers
Problem is, official mingw uses gcc 3.4.5, and they say its not going to change in the near future
Sahasranaman MS
+3  A: 

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.

David Thornley
+1  A: 

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.

Michael Burr
A: 

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.

bk1e