tipos tipo real programacion enteros datos dato c++ c integer-overflow

c++ - programacion - tipo de dato real



¿Por qué C y C++ no han incorporado formas de verificar los desbordamientos de enteros? (6)

¿Por qué? Bueno, porque no estaban en C cuando C ++ comenzó a partir de eso, y porque desde entonces nadie propuso tales funciones y logró convencer a los compiladores y miembros de los comités de que son lo suficientemente útiles como para proporcionarlas.

Tenga en cuenta que los compiladores provide este tipo de intrínsecos, por lo que no es que estén en contra de ellos.

Tenga en cuenta también que hay proposiciones para estandarizar cosas como la aritmética de punto fijo y los tipos enteros de precisión sin límites .

Así que probablemente es solo que no hay suficiente interés.

¿Por qué C y C ++ no proporcionan un conjunto de operaciones provistas de implementación para realizar cada una de las operaciones enteras básicas con la verificación de desbordamiento provista (por ejemplo, un bool safeAdd(int *out, int a, int b) ).

Tal como lo entiendo, la mayoría de los conjuntos de instrucciones tienen formas de saber si las operaciones se desbordaron (por ejemplo, el desbordamiento de x86 y los indicadores de acarreo) y también definirían que sucedería en el caso de los enteros con signo.

Como tal, ¿no deberían los compiladores ser capaces de hacer un trabajo mucho mejor, creando operaciones más simples y más rápidas, que lo que es posible codificar en C y C ++?


C y C ++ siguen un principio central de "No pagas por lo que no necesitas". Por lo tanto, las operaciones aritméticas predeterminadas no se desviarán de la instrucción única de la arquitectura subyacente para las operaciones aritméticas.

No puedo decir por qué no hay una función de biblioteca estándar para agregar dos enteros y detectar desbordamientos. En primer lugar, parece que el lenguaje define el desbordamiento de enteros con signo como un comportamiento indefinido :

En el lenguaje de programación C, el desbordamiento de enteros con signo provoca un comportamiento indefinido,

Teniendo en cuenta que hay varias formas de implementar un entero con signo (complemento de uno, complemento de dos, etc.) y cuando se creó C, estas arquitecturas prevalecieron, por lo que es comprensible que esto no esté definido. Sería difícil implementar una función de C pura "segura *" sin mucha información sobre la plataforma subyacente. Se podría hacer sabiendo en una CPU por CPU.

Aún así eso no lo hace imposible. Definitivamente me interesaría si alguien pudiera encontrar propuestas para los organismos de estándares C o C ++ con ayudantes de desbordamiento más seguros y poder ver por qué fueron rechazados.

En cualquier caso, hay muchas formas en la práctica para detectar desbordamientos aritméticos y bibliotecas para ayudar.


La pregunta aparece regularmente.

Primero, recuerde que C se define como portátil y eficiente . Como tal, fue diseñado para proporcionar solo operaciones que fueron soportadas por una gran cantidad de hardware (probablemente incluso antes de que x86 viera la luz).

En segundo lugar, una serie de compiladores proporcionan ( o planean proporcionar ) incorporaciones para tales operaciones, de modo que los usuarios puedan usar tipos de clase que usen esas incorporaciones bajo el capó. La calidad de las implementaciones de los incorporados no es tan importante (aunque lo es) como el hecho de que un compilador consciente de su significado pueda optimizar las comprobaciones cuando sean probadamente inútiles.

Por último, hay otras formas de comprobar realmente los programas. Por ejemplo, el análisis estático o los modos de compilación especiales y las pruebas unitarias pueden detectar esas fallas antes y evitar la necesidad (más o menos completamente) de incrustar esas verificaciones de desbordamiento en las versiones de la versión.


Porque rara vez se necesita. ¿Cuándo necesitaría realmente detectar un desbordamiento de enteros? En casi todas las situaciones en las que necesita verificar un rango, generalmente es usted quien define el rango real porque este rango depende completamente de la aplicación y el algoritmo.

¿Cuándo realmente necesita saber si un resultado ha sobrepasado el rango de int lugar de saber si un resultado está dentro del dominio permitido para un algoritmo en particular o si un índice está dentro de los límites de una matriz? Es usted quien da a sus variables una semántica, la especificación del idioma solo le proporciona los rangos de tipos generales y, si elige un tipo cuyo rango no se adapta a sus necesidades, entonces es su culpa.

El desbordamiento de enteros es UB, porque rara vez te importa realmente. Si mi unsigned char desborda durante las operaciones, es probable que haya elegido el tipo incorrecto para acumular 10 millones de números. Pero conocer el desbordamiento durante el tiempo de ejecución no me ayudará, ya que mi diseño está roto de todos modos.


Probablemente porque no hay demanda para ello. El desbordamiento aritmético es un comportamiento indefinido, expresamente para permitir que las implementaciones realicen dichas comprobaciones. Si los vendedores de compiladores pensaran que hacerlos venderían más compiladores, lo harían.

En la práctica, sería muy, muy difícil para un compilador hacerlas más efectivamente que el programador. Es un procedimiento bastante estándar para validar los rangos de todas las entradas numéricas, a rangos en los que puede probar que las operaciones posteriores no pueden desbordarse. Todos los buenos programadores hacen esto por costumbre. Así que esto significa uno rápido if inmediatamente después de la entrada, y no hay más comprobaciones.

Aún así, se sabe que los programadores cometen errores, y es fácil olvidarse de corregir la validación cuando se cambian los cálculos más adelante. Me gustaría ver tal característica en un compilador. Pero al parecer, no ayudará a vender compiladores, o al menos los proveedores creen que no lo hará, así que no lo conseguimos.


Una mejor pregunta podría ser: ¿por qué el desbordamiento de enteros es un comportamiento indefinido? En la práctica, el 99.9% de todas las CPUs usan un complemento de dos y un bit de acarreo / desbordamiento. Por lo tanto, en el mundo real, a nivel de ensamblador / código de operación, los desbordamientos de enteros siempre están bien definidos. De hecho, una gran cantidad de ensambladores, o C relacionada con el hardware, depende en gran medida de los desbordamientos de enteros bien definidos (en particular los controladores para hardware de temporizador).

El lenguaje C original, antes de la estandarización, probablemente no consideraba este tipo de cosas en detalle. Pero cuando C se estandarizó por ANSI e ISO, tuvieron que seguir ciertas reglas de estandarización. No se permite que las normas ISO se inclinen hacia una determinada tecnología y, por lo tanto, otorgan ciertas ventajas a la empresa en la competencia.

Así que tenían que considerar que algunas CPU podrían implementar cosas oscuras como el complemento de uno, "signo y magnitud" o "alguna forma definida por la implementación". Tenían que permitir ceros firmados, bits de relleno y otros mecanismos enteros con signo ocultos.

Debido a esto, el comportamiento de los números firmados se volvió maravillosamente borroso. No puede darse cuenta de lo que sucede cuando un entero con signo en C se desborda, porque los enteros con signo se pueden expresar en el complemento de dos, el complemento de uno o posiblemente alguna otra locura definida por la implementación. Por lo tanto, los desbordamientos de enteros son un comportamiento indefinido.

La solución sensata a este problema no sería inventar algunas comprobaciones de rango seguro, sino afirmar que todos los enteros con signo en el lenguaje C tendrán el formato de complemento a dos, el final de la historia. Entonces, un char sin firmar siempre sería 0 a 127 y se desbordaría a -128 y todo estaría bien definido. Pero la burocracia estándar artificial evita que el estándar se vuelva sano.

Hay muchas cuestiones como esta en el estándar C. Alineación / relleno, endianess etc.