Pregunta

Estoy intentando construir cairomm para gtkmm en Windows usando mingw.La compilación se interrumpe en una llamada a una función que tiene un parámetro que realiza una reinterpret_cast de un bool a un void*.

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

Aquí es donde el código se rompe y el motivo es "reinterpret_cast no válido de bool a void*".¿Por qué sucede esto y cómo puedo modificar esta línea para que se compile?Necesitas ayuda

¿Fue útil?

Solución

Veo que estos son datos de usuario y usted tiene control sobre lo que se hace con el valor, convierta el bool a int primero: reinterpret_cast<void *> (static_cast<int> (true)). Hacer esto tiene sentido porque el parámetro void * toma el lugar de las funciones de plantilla en esta biblioteca ANSI-C. Todo lo que necesitas es un valor verdadero / falso. Por lo tanto, no debería haber peligro en codificar temporalmente esto como un puntero, siempre que esté bien documentado como tal. Realmente, sería mejor con esto: reinterpret_cast<void *> (1) o reinterpret_cast<void *> (+true).

Otros consejos

Parece que debería funcionar, de acuerdo con el estándar. La sección 3.9.1-7 dice que bool es un tipo integral, y 5.2.10-5 dice que un valor de tipo integral se puede convertir explícitamente en un puntero usando reinterpret_cast. Parece que su compilador no es completamente estándar.

¿Podría salirse con la suya cambiando " true " a un 1? La conversión entre enteros y tipos de puntero es una tradición antigua y deshonrosa en C y, por lo tanto, en C ++, y sería sorprendente encontrar un compilador que no lo hiciera.

O, si realmente tienes que hacer esto, prueba (void *) true. Luego lávate las manos.

reinterpret_cast es una mala idea . Cuéntanos más sobre el problema que estás tratando de resolver y quizás encontremos una solución sin recurrir a la reinterpretación. ¿Por qué quieres convertir bool a void *?

El único compilador que tengo que se queja de esto es GCC (MinGW con GCC 3.4.5), y no estoy seguro de por qué. El estándar parece indicar claramente que esto está permitido:

  

3.9.1 Tipos fundamentales

     

...

     

Tipos bool, char, wchar_t y el   los tipos enteros con y sin signo son   colectivamente llamados tipos integrales.

     

5.2.10 Reinterpretar reparto:

     

...

     

Un valor de tipo integral o   tipo de enumeración puede ser explícitamente   convertido en puntero.

Dicho esto, solución alternativa de monjardin de usar reinterpret_cast<void *> (static_cast<int> (true)) o reinterpret_cast<void *> (1) son soluciones razonables.

Falla porque la conversión no tiene sentido: está tomando un valor booleano verdadero / falso y le pide a la compilación que interprete esto como un puntero, que en términos contundentes es una ubicación de memoria. Los dos no están ni remotamente relacionados.

Pruebe una versión más nueva de su compilador. Acabo de probar y este elenco funciona al menos en gcc 4.1 y superior. Sin embargo, no sé exactamente cómo se correlacionan las versiones de gcc con las versiones de mingw.

En algunas situaciones, es muy deseable que el compilador advierta o produzca un error en código como reinterpret_cast<void*>(true), aunque este código es aparentemente C++ legal.Por ejemplo, ayuda a migrar a plataformas de 64 bits.

Convertir un puntero de 64 bits en un tipo integral que sea más pequeño que un puntero (como int o bool) suele ser un error:estás truncando el valor del puntero.Además, la especificación de C++ no parece garantizar que se pueda convertir directamente un puntero en un tipo integral más pequeño (énfasis añadido):

5.2.10.4.Un puntero se puede convertir explícitamente a cualquier tipo integral. lo suficientemente grande como para sostenerlo.La función de mapeo está definida por la implementación.

Del mismo modo, convertir un tipo integral más pequeño en un puntero de 64 bits (como con reinterpret_cast<void*>(true)) suele ser un error también:el compilador tiene que rellenar los bits superiores del puntero con algo;¿Se completa con ceros o se extiende con signos?A menos que esté escribiendo código específico de plataforma de bajo nivel para acceso a E/S asignadas en memoria o DMA, normalmente no querrá hacer esto en absoluto, a menos que esté haciendo algo complicado (como introducir un valor booleano en un puntero ).Pero la especificación de C++ no parece decir mucho sobre este caso, aparte de que está definido por la implementación (nota al pie omitida):

5.2.10.5.Un valor de tipo integral o tipo de enumeración se puede convertir explícitamente en un puntero.*

Un puntero convertido a un número entero de tamaño suficiente (si existe alguno en la implementación) y nuevamente al mismo tipo de puntero tendrá su valor original;De lo contrario, las asignaciones entre punteros y números enteros están definidas por la implementación.

@monjardin sugirió reinterpret_cast<void*>(static_cast<int>(true)).Si el origen del error fue la falta de coincidencia entre el tamaño del tipo integral y el tamaño del puntero, entonces esto funcionará en la mayoría de las plataformas de 32 bits (donde ambas int y void* son de 32 bits) pero fallan en la mayoría de las plataformas de 64 bits (donde int es de 32 bits y void* es de 64 bits).En ese caso, reemplazando int en esta expresión con un tipo entero del tamaño de un puntero como uintptr_t o DWORD_PTR (en Windows) debería funcionar, ya que las conversiones entre bool y se permiten números enteros del tamaño de un puntero, al igual que conversiones entre números enteros del tamaño de un puntero y punteros.

Las versiones posteriores de GCC tienen lo siguiente opciones de supresión de advertencias, pero no para C++:

-Wno-int-to-pointer-cast (solo C y Objective-C)
Suprime las advertencias de conversiones al tipo de puntero de un número entero de diferente tamaño.

-Wno-pointer-to-int-cast (solo C y Objective-C)
Suprime las advertencias de conversiones de un puntero a un tipo entero de diferente tamaño.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top