online - ¿Por qué C++ permite la conversión implícita de int a unsigned int?
c++ program (5)
Considere el siguiente código:
void foo(unsigned int x)
{
}
int main()
{
foo(-5);
return 0;
}
Compila sin problemas. Errores como este pueden causar muchos problemas y son difíciles de encontrar. ¿Por qué C ++ permite tal conversión?
@ user168715 tiene razón. C ++ se diseñó inicialmente para ser un superconjunto de C, simulando ser lo más compatible posible. La filosofía "C" es entregar la mayor parte de la responsabilidad al programador, en lugar de rechazar las cosas peligrosas. Para los programadores de C es el paraíso, para los programadores de Java, es el infierno ... una cuestión de gustos.
Investigaré los estándares para ver exactamente dónde está escrito, pero no tengo tiempo para esto ahora. Voy a editar mi respuesta tan pronto como pueda.
También estoy de acuerdo en que parte de la libertad heredada puede llevar a errores que son realmente difíciles de depurar, por lo que estoy agregando a lo que se dijo que en g ++ puede activar una advertencia para evitar que -Wconversion
este tipo de error: .
Avisar de conversiones implícitas que puedan alterar un valor. Esto incluye conversiones entre real y entero, como abs (x) cuando x es doble; conversiones entre firmado y sin firmar, como ui = -1 sin firmar; y conversiones a tipos más pequeños, como sqrtf (M_PI). No avise para conversiones explícitas como abs ((int) x) y ui = (sin signo) -1, o si el valor no se modifica por la conversión como en abs (2.0). Las advertencias sobre las conversiones entre enteros con signo y sin signo se pueden deshabilitar utilizando -Wno-sign-conversion.
Para C ++, también advierta sobre la confusa resolución de sobrecarga para las conversiones definidas por el usuario; y conversiones que nunca utilizarán un operador de conversión de tipo: conversiones para anular, el mismo tipo, una clase base o una referencia a ellos. Las advertencias sobre las conversiones entre enteros con signo y sin signo se desactivan de forma predeterminada en C ++, a menos que -Wsign-conversion esté habilitado explícitamente.
Otros compiladores pueden tener banderas similares.
En el momento de la norma C original, muchos compiladores (¿todos?) Ya permitían la conversión. Sobre la base de la justificación C, parece que ha habido poca discusión (si la hay) sobre si se deberían permitir tales conversiones implícitas. Para cuando llegó C ++, tales conversiones implícitas eran lo suficientemente comunes como para eliminarlas que hubieran hecho que el lenguaje fuera incompatible con una gran cantidad de código C. Probablemente habría hecho a C ++ más limpio; sin duda lo habría hecho mucho menos usado, hasta el punto de que probablemente nunca habría ido más allá de la etapa de "C con Clases", e incluso eso sería una nota a pie de página mayormente ignorada en la historia de los laboratorios Bell.
La única pregunta real a lo largo de esta línea fue entre las reglas de "preservación de valor" y "preservación no firmada" cuando se promueven valores "más pequeños" sin firmar que int. La diferencia entre los dos surge cuando tiene (por ejemplo) un short sin firmar que se agrega a un char sin firmar.
Las reglas de conservación sin firmar dicen que promueves ambas a int sin firmar. Las reglas de preservación de valores dicen que promueve ambos valores a int
, si puede representar todos los valores del tipo original (por ejemplo, el caso común de caracteres de 8 bits, 16 bits en corto y 32 bits en formato int). Por otro lado, si int y short son ambos de 16 bits, por lo que int no puede representar todos los valores de short sin signo, entonces usted promueve el short sin signo al int sin signo (tenga en cuenta que todavía se considera una promoción, aunque solo sucede cuando es realmente no una promoción, es decir, los dos tipos son del mismo tamaño).
Para bien o para mal, (y se ha discutido en ambas direcciones muchas veces), el comité eligió la preservación del valor en lugar de las promociones de la preservación sin firmar. Sin embargo, tenga en cuenta que se trata de una conversión en la dirección opuesta: en lugar de firmar con sin firmar, se trata de si convierte sin firmar en firmado.
La respuesta corta es porque C originalmente apoyó dichas conversiones y no querían romper el software existente en C ++.
Tenga en cuenta que algunos compiladores advertirán sobre esto. Por ejemplo, g++ -Wconversion
advertirá sobre esa construcción.
En muchos casos, la conversión implícita es útil, por ejemplo, cuando se utilizó int
en los cálculos, pero el resultado final nunca será negativo (conocido por el algoritmo y, opcionalmente, se afirma).
EDITAR: explicación probable adicional: recuerde que originalmente C era un lenguaje mucho más vago que C ++ ahora. Con las declaraciones de funciones de estilo K&R, el compilador no habría tenido forma de detectar tales conversiones implícitas, así que, ¿por qué molestarse en restringirlas en el idioma? Por ejemplo, su código se vería más o menos así:
int foo(x)
unsigned int x
{
}
int main()
{
foo(-5);
return 0;
}
mientras que la declaración sola habría sido int foo(x);
El compilador realmente confió en el programador para pasar los tipos correctos a cada llamada de función y no realizó conversiones en el sitio de la llamada . Luego, cuando la función realmente fue llamada, los datos en la pila (etc.) se interpretaron de la manera indicada por la declaración de la función.
Una vez que se escribió un código que dependía de ese tipo de conversión implícita, se habría vuelto mucho más difícil eliminarlo de ANSI C incluso cuando se agregaron prototipos de funciones con información de tipo real. Esto es probable por qué permanece en C incluso ahora. Luego llegó C ++ y, una vez más, decidió no romper la compatibilidad hacia atrás con C y continuar permitiendo tales conversiones implícitas.
Porque el estándar permite la conversión implícita de tipos signed
a unsigned
.
Además, (int)a + (unsigned)b
da como resultado unsigned
; este es un estándar de c ++.
- Solo otra peculiaridad de un lenguaje que tiene muchas peculiaridades tontas.
- La conversión está bien definida para envolver, lo que puede ser útil en algunos casos.
- Es compatible con versiones anteriores de C, que lo hace por las razones anteriores.
Elige tu opción.