2010-11-18 8 views
6

No creo que sea posible evitar por completo el estilo C al escribir C++. Me sorprendió find out que tenía que utilizar una conversión de estilo C para evitar una advertencia del compilador de truncamiento:¿Es posible evitar completamente los moldes de estilo C en C++?

short value_a = 0xF00D;      // Truncation warning in VS2008 
short value_b = static_cast<short>(0xF00D); // Truncation warning in VS2008 
short value_c = (short)0xF00D;    // No warning! 

¿Hay otros escenarios donde no hay C++ - sustituto de estilo para una conversión de estilo C?

+7

'short value_c (0xF00D)' - también: ¿qué compilador te da advertencias de truncamiento? Mi GCC es lo suficientemente inteligente como para no en las tres situaciones. –

+0

C++ proyecta la cobertura de todos los usos del operador de elenco en C. – wilhelmtell

+8

En lo que respecta al idioma, no hay diferencia entre 'static_cast' y un molde de estilo C en este caso.Si el compilador decidió dar una advertencia de que "son las 3AM hora local, realmente debería irse a la cama", es gratis hacerlo ... –

Respuesta

2

Usted está tratando de ofuscar su código, es así de simple. Y el compilador tiene toda la razón al decírtelo.

Si tiene una idea precisa de cuál debe ser el valor asignado, úselo. Supongo que tiene una presunción infundada de que short tiene 16 bits de ancho y que la representación del signo de la máquina de destino es complemento de dos. Si es así, asigne -4083 a su variable. Si solo necesita su variable como un vector de bits, use un tipo sin signo.

Por lo que C se refiere a la norma simplemente dice acerca de la conversión de un tipo de número entero a otro:

lo contrario, se firmó el nuevo tipo y el valor no puede ser representado en ella; bien el resultado es definido por la implementación o una señal definida por la implementación es planteada.

Imagino que el punto de vista de C++ con este respecto no es muy diferente. Otras respuestas mencionan casos de frontera donde en C++ necesitarías un elenco de estilo `C'para anular todas las comprobaciones de tipo que C++ te da. Sentir la necesidad de ellos es una indicación de mal diseño.

La caja que da como ejemplo ciertamente no es para la que encontraría ninguna circunstancia válida.

-3

En estos casos, puede usar reinterpret_cast. Estaba destinado a reemplazar un modelo de estilo C sin marcar. La nota típica aquí: esto es un casteo no verificado, y se debe evitar cuando sea posible usando el otro disponible: const_cast, dynamic_cast, etc.

+1

En realidad, el molde de estilo C puede ser una de las 5 combinaciones de 'static_cast',' const_cast' y 'reinterpret_cast'. – kennytm

+0

Buena respuesta ... bla, bla, bla ... yadda, yadda ... no use este método a menos que sea absolutamente necesario. –

+12

No creo que se deba usar un 'reinterpret_cast' para truncar un' int' en un 'short'. Nunca. – sbi

2

Sí, es completamente posible.

Nunca utilizo moldes de estilo C. Puedo escribir cientos de miles de líneas de código sin tener que volver a usar reinterpret_cast, C++ cierra primo al estilo C. Las únicas veces que tengo que usar reinterpret_cast es cuando hago la programación de socket - un dominio bastante estrecho, a grandes rasgos.

Usted No necesidad de usar C-estilo yesos, tampoco. En su other post, usted ha dicho

tan sólo pudiera utilizar un valor negativo,

short my_value = -4083; 

pero en mi código es mucho más comprensible para utilizar hexadecimal.

De modo que en este caso no tenías que usar el modelo. Tú eliges.

+0

Recientemente, tuve que usar un reinterpret_cast para convertir de una matriz de caracteres sin signo en bruto a una instancia de una estructura. ¿Es esto algo así como lo que estabas diciendo sobre los enchufes? –

+0

@San. Tal vez. :) Tendría que verlo. –

+2

Volvería a votar para contrarrestar el inexplicable voto negativo, pero me quedé sin votos para hoy. ': (' Pero, sí, también para mí, la relación LoC/'reinterpret_cast' está en algún lugar de los números de seis dígitos, y no creo que haya usado un molde de estilo c en código C++ en el último década. – sbi

0

Me sorprendió descubrir que necesitaba usar una conversión de estilo C para evitar una advertencia del compilador truncamiento

lo veo al revés: Se utiliza una conversión de estilo C a previene que el compilador le advierta, y veo esto como una desventaja severa del lanzamiento de estilo C.

si sientes que sabes lo que estás haciendo, entonces cierra el compilador para este caso utilizando una compilación específica. Por ejemplo, para VC usar algo como

#pragma warning(push, disable: XXXX) 
// code goes here 
#pragma warning(pop) 
+0

Nunca pensé que haría esto, probablemente porque usamos al menos 3 compiladores/compiladores diferentes para compilar familias el mismo código para diferentes objetivos, y un elenco me parece más limpio que hacer todas las comprobaciones del preprocesador para determinar el compilador cada vez que podría haber utilizado un elenco. ¿Cuál es tu pensamiento? –

+2

@San: He sido parte de un proyecto donde la mayoría del código fue compilado por media docena de compiladores diferentes y versiones de los mismos, multiplicado por varias implementaciones de std lib diferentes. Aún así, la mayoría de nosotros tratamos de evitar el uso de moldes de estilo C, porque cierran el compilador por completo, impidiendo que señale errores. (Y cada error encontrado durante la compilación vale 1000 encontrados en tiempo de ejecución, generalmente por un cliente.) Experiencia IME __ los compiladores variarán enormemente en lo que advierten__ de todos modos, por lo que generalmente debe cerrarlos (selectivamente) en diferentes lugares . – sbi

+0

Interesante, gracias. –

10

En C++, la conversión de estilo C se define (§ 5.4) en términos de C++ - estilo arroja. Entonces, por cada elenco que se puede hacer al estilo C, hay un molde de estilo C++ coincidente (casi).

El "casi" es que los modelos de estilo C ignoran la accesibilidad de la clase base. Es decir, no hay un equivalente de C++ - Reparto estilo para lo siguiente:

struct foo {}; 
struct bar : private foo {}; 

bar b; 
foo* f = (foo*)&b; // only way this can be done in a well-defined manner 

lo tanto, no se no es estrictamente de habla completamente posible zanja de estilo C arroja. Pero la cantidad de áreas en las que una (combinación de) estilos de C++ no es suficiente es poca.


Lo anterior es la "respuesta de idioma". Lo que estás experimentando no tiene nada que ver con los lanzamientos de estilo C contra los lanzamientos de C++, sino solo con la implementación del compilador. Las advertencias son absolutamente específicas de la implementación y no tienen nada que ver con C++.

así que no hacen el error de usar sus hallazgos en este compilador particular, en esta situación particular para concluir las cosas sobre C++, en general,.

+0

'foo * f = reinterpret_cast (& b)'?Aunque asumo que olvidó el '&' de 'foo * f = (foo *) b'. –

+0

@Travis: No. El resultado de 'reinterpret_cast' está ** definido por la implementación **. Con el elenco estilo C, actúa como un 'static_cast' que no está definido por la implementación. – GManNickG

+0

@GMan: claramente, * no * actúa como un 'static_cast' en el caso del OP. De lo contrario, daría una advertencia. Como no hay ninguno, concluyo que actúa como el 'reinterpret_cast' aquí. O el compilador tiene un error. Elige tu opción. –

0

Hay 4 modelos de estilo C++, const_cast, reinterpret_cast, static_cast y dynamic_cast. Funcionan de la siguiente manera:

// const_cast casts away constness or adds it 
const int const_integer = 5; 
const_cast<int>(const_integer) = 3; 

// static_cast will perform standards defined casts and will 
// cast up or down a c++ inheritance hierarchy without checking the result of the cast 
struct b {}; 
struct a : public b {}; 
struct c {}; 
double value = static_cast<double>(0.0f); 
b* b_value = new b; 
a* a_value = static_cast<a*>(b_value); 

// dynamic_cast will perform any cast that static_cast will, but will check to see 
// if the cast makes sense. If the values are not pointers, this cast can throw 
b* value_b = new b; 
a* value_a = new a; 
b* new_b = dynamic_cast<b*>(value_a); // will return NULL 
a* new_a = dynamic_cast<a*>(value_b); // will not return NULL  

// reinterpret_cast will change any type to any other type, as long as the constness of the types is the same. 
// the behavior of this cast is implementation specific. 
double* a = new double; 
*a = 0.0f; 
int *b = reinterpret_cast<int*>(a); 

Un molde de c-estilo en C++ simplemente trata de realizar esos moldes en un orden específico hasta que uno de ellos trabaja. Esa orden es el siguiente:

  • un const_cast
  • un static_cast
  • un static_cast seguido de un const_cast
  • un reinterpret_cast, o
  • un reinterpret_cast seguido de un const_cast.

Así que, en resumen, puede hacer cualquier elenco de estilo c en C++, porque un molde de estilo c en C++ es solo una disposición de los moldes de estilo C++. ¿Consíguelo?

+0

Ver mi respuesta, entonces. No todos los casos pueden ser reemplazados con moldes de estilo C++. – GManNickG

+1

Su primer ejemplo 'const_cast' da como resultado un comportamiento indefinido. –

+0

¿Cómo resulta en un comportamiento indefinido? – tyree731

Cuestiones relacionadas