Pregunta

Leí un poco en c especificación que las variables sin firmar (en particular Corto sin firmar int) Realice algunos llamados envolver alrededor En el desbordamiento entero, aunque no pude encontrar nada en las variables firmadas, excepto que me fui con comportamiento indefinido.

Mi profesor me dijo que sus valores también se envuelven (tal vez solo se refería a GCC). ¡Pensé que los bits simplemente se truncaron y los bits con los que me fui me dan un valor extraño!

Lo que se envuelve es y cómo es diferente de solo truncar bits.

¿Fue útil?

Solución

Las variables enteras firmadas no tienen un comportamiento envolvente en el lenguaje C. El desbordamiento entero firmado durante los cálculos aritméticos produce comportamiento indefinido. Nota Por cierto, que el compilador GCC que mencionó es conocido por implementar Semántica de desbordamiento estricto En optimizaciones, lo que significa que aprovecha la libertad proporcionada por tales situaciones de comportamiento indefinidas: el compilador de GCC asume que los valores de enteros firmados nunca se extienden. Eso significa que el GCC en realidad es uno de los compiladores en los que no poder Confíe en el comportamiento envolvente de los tipos enteros firmados.

Por ejemplo, el compilador de GCC puede suponer que para la variable int i la siguiente condición

if (i > 0 && i + 1 > 0)

es equivalente a un mero

if (i > 0)

Esto es exactamente lo que Semántica de desbordamiento estricto medio.

Los tipos enteros sin firmar implementan la aritmética de módulos. El módulo es igual 2^N dónde N es el número de bits en la representación de valor del tipo. Por esta razón, los tipos de enteros sin firmar parecen envolver sobre el desbordamiento.

Sin embargo, el lenguaje C nunca realiza cálculos aritméticos en dominios más pequeños que el de int/unsigned int. Escribe unsigned short int que mencionas en tu pregunta normalmente será promovido para escribir int en expresiones antes de que comiencen cualquier cálculo (suponiendo que el rango de unsigned short encaja en el rango de int). Lo que significa que 1) los cálculos con unsigned short int se preformará en el dominio de int, con el desbordamiento sucediendo cuando int Los desbordamientos, 2) el desbordamiento durante tales cálculos conducirá a un comportamiento indefinido, no a un comportamiento envolvente.

Por ejemplo, este código produce una envoltura

unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */

Mientras este código

unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */

conduce a un comportamiento indefinido.

Si no int El desbordamiento ocurre y el resultado se convierte en un unsigned short int Tipo, nuevamente se reduce por Modulo 2^N, que aparecerá como si el valor hubiera envuelto.

Otros consejos

Imagine que tiene un tipo de datos que tiene solo 3 bits de ancho. Esto le permite representar 8 valores distintos, de 0 a 7. Si agrega de 1 a 7, "envolverá" de regreso a 0, porque no tiene suficientes bits para representar el valor 8 (1000).

Este comportamiento está bien definido para tipos sin firmar. Está no Bien definido para los tipos firmados, porque existen múltiples métodos para representar valores firmados, y el resultado de un desbordamiento se interpretará de manera diferente en función de ese método.

Magnitud del signo: el bit superior representa el signo; 0 para positivo, 1 para negativo. Si mi tipo tiene tres bits de ancho nuevamente, entonces puedo representar valores firmados de la siguiente manera:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -0
101  = -1
110  = -2
111  = -3

Dado que se ocupa un bit para el letrero, solo tengo dos bits para codificar un valor de 0 a 3. Si agrego 1 a 3, me desbordaré con -0 como resultado. Sí, hay dos representaciones para 0, una positiva y otra negativa. No encontrará una representación de significación de signos con tanta frecuencia.

El complemento de uno: el valor negativo es el bitwise-inverse del valor positivo. Nuevamente, usando el tipo de tres bits:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -3
101  = -2
110  = -1 
111  = -0

Tengo tres bits para codificar mis valores, pero el rango es [-3, 3]. Si agrego de 1 a 3, me desbordaré con -3 como resultado. Esto es diferente del resultado de signos de signos anteriores. Nuevamente, hay dos codificaciones para 0 utilizando este método.

Two's-Complement: el valor negativo es el inverso bit a bit del valor positivo, más 1. En el sistema de tres bits:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -4
101  = -3
110  = -2
111  = -1

Si agrego de 1 a 3, me desbordaré con -4 como resultado, que es diferente de los dos métodos anteriores. Tenga en cuenta que tenemos un rango de valores ligeramente mayor [-4, 3] y solo una representación para 0.

El complemento de dos es probablemente el método más común para representar los valores firmados, pero no es el único, por lo tanto, el estándar C no puede garantizar lo que sucederá cuando desbordes un tipo entero firmado. Entonces deja el comportamiento indefinido Por lo tanto, el compilador no tiene que lidiar con la interpretación de múltiples representaciones.

los comportamiento indefinido Proviene de problemas de portabilidad tempranos cuando los tipos de enteros firmados podrían representarse como signos y magnitud, el complemento o el complemento de dos.

Hoy en día, todas las arquitecturas representan enteros como complemento de dos que se envuelven. Pero tenga cuidado: dado que su compilador tiene razón al asumir que no ejecutará un comportamiento indefinido, puede encontrar errores extraños cuando la optimización está activada.

En un entero de 8 bits firmado, la definición intuitiva de envoltura podría parecer pasar de +127 a -128, en el complemento de dos: 0111111 (127) y 1000000 (-128). Como puede ver, ese es el progreso natural de incrementar los datos binarios, sin considerar que representa un entero, firmado o sin firmar. Controlar intuitivamente, el desbordamiento real tiene lugar cuando se mueve de -1 (11111111) a 0 (00000000) en el sentido de envoltura del entero sin firmar.

Esto no responde a la pregunta más profunda de cuál es el comportamiento correcto cuando un entero firmado se desborda porque no hay un comportamiento "correcto" de acuerdo con el estándar.

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