2009-08-14 15 views
5

que tienen el ejemplo siguiente, compilado en VS2005, el nivel 4 de advertencia:¿Por qué es * = diferente respecto a la pérdida de datos en la conversión?

int main(int argc, char *argv[]) 
{ 
    short s = 2; 
    short t = 3; 

    t *= s; // warning C4244: '*=' : conversion from 'int' to 'short', possible loss of data 
    t = t * s; 
} 

No me parece que debe haber un aviso en cualquiera de las líneas.

¿* * crea una conversión implícita a int por algún motivo?

EDIT:

parece que la falta de advertencia en la segunda línea (y en VS2008) son los verdaderos preguntas.

Gracias por las respuestas.

+0

No sucede en 2008. –

+0

Uso de VC2008 construido con (/ W4) -> ¡No recibo la advertencia! – AraK

+0

No recibí una advertencia en VS2005. Tal vez puede publicar sus opciones de compilador? –

Respuesta

12

Sí. Todos los operadores aritméticos en C++ se definen en int y más. Cuando multiplicas dos short s (no importa si usas * o *=) ambos se convierten primero a int. Esto está cubierto por ISO C++ 5 [expr]/9:

Muchos operadores binarios que esperan operandos de tipo aritmético o de enumeración causan conversiones y producen tipos de resultados de forma similar. El propósito es producir un tipo común, que también es el tipo del resultado. Este patrón se denomina conversiones aritméticas habituales, que se definen de la siguiente manera:

  • Si cualquier operando es del tipo double long, el otro se convertirá a double largo.
  • De lo contrario, si cualquier operando es doble, el otro se convertirá en doble.
  • De lo contrario, si cualquiera de los operandos es flotante, el otro se convertirá en flotante.
  • De lo contrario, las promociones integrales (4.5) se realizarán en ambos operandos.
  • Entonces, si cualquiera de los operandos no tiene firma, el otro se convertirá a largo sin signo.
  • De lo contrario, si un operando es un int largo y el otro unsigned int, entonces si un int largo puede representar todos los valores de un int sin firmar, el int sin firmar se convertirá en un int largo; de lo contrario, ambos operandos se convertirán a unsigned long int.
  • De lo contrario, si alguno de los operandos es largo, el otro se convertirá en largo.
  • De lo contrario, si ninguno de los operandos está sin firmar, el otro se convertirá en unsigned.

[Nota: en caso contrario, el caso único que queda es que ambos operandos son int]

y 4,5 [conv.prom]:

1 Un valor p de tipo char, firmado char, unsigned char, short int o unsigned short int se pueden convertir a un rvalue de tipo int si int puede representar todos los valores del tipo de fuente; de lo contrario, el valor de origen r se puede convertir a un valor r de tipo unsigned int.

2 Un valor p de tipo wchar_t (3.9.1) o un tipo de enumeración (7.2) se puede convertir a un valor p de la primera de las siguientes tipos que se pueden representar todos los valores de su tipo subyacente: int, unsigned int , largo o sin signo largo.

3 Un valor r para un campo de bits integral (9.6) se puede convertir a un valor r de tipo int si int puede representar todos los valores del campo de bits; de lo contrario, se puede convertir a unsigned int si unsigned int puede representar todos los valores del bit-field. Si el campo de bit es aún más grande, no se aplica ninguna promoción integral. Si el campo de bit tiene un tipo enumerado, se trata como cualquier otro valor de ese tipo para fines de promoción.

4 Un valor de tipo bool se puede convertir a un valor r de tipo int, con falso que se convierte en cero y verdadero convirtiéndose en uno.

5 Estas conversiones se denominan promociones integrales.

¿Por qué sólo se da una advertencia en una sola línea, pero no tanto está claro, sin embargo.

3

Creo que la respuesta es here.

Cita:

mayoría de los operadores C realizan tipo conversiones para llevar a los operandos de una expresión a un tipo común o para extender valores cortos a la tamaño entero utilizado en operaciones de la máquina.

4

El resultado de un short * short podría desbordarse en un corto, por lo que es probable que se guarde el resultado intermedio en un int en el segundo ejemplo. En todo caso, ambos deberían tener advertencias.

El primero de ellos es, probablemente, quejándose porque está almacenando el resultado directamente en el valor a corto original, mientras que la segunda es la creación de un int intermedia y luego fundición que a un corto (siendo una operación con pérdidas, pero muchos compiladores no lo hará quejar).

0

Esto parece ser una advertencia muy extraña en general. Algunas observaciones:

short s = 12345; 
s *= 0xffff;  // no warning 
s *= (int)0xffff; // no warning 
s *= 0x10000;  // C4244 
s *= -0x8000;  // no warning 
s *= -0x8001;  // C4244 

short t = -12345; 
s *= t;   // no warning 
s *= (int)t;  // no warning 
s *= (unsigned)t; // no warning 

s *= (int)t * 0xffff; // no warning 
s *= (int)t * 0x10000; // C4244 

no parece que se preocupan por los operadores específicos - todos +-*/ dan los mismos resultados. Parece que en realidad no solo observa los tipos de expresiones, sino también los literales involucrados, y tan pronto como cruzas el umbral mágico, aparece la advertencia.

Cuestiones relacionadas