2011-11-06 32 views
29

Parece que no puedo encontrar las partes relevantes en el estándar C definiendo completamente el comportamiento del operador unario negativo con operandos sin signo.C: comportamiento de operador unitario negativo con operandos sin signo

El estándar C++ 2003 (sí, C++, oso conmigo durante unas pocas líneas) dice en 5.3.1c7: The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of bits in the promoted operand.

La norma C 1999, sin embargo, no incluye una declaración tan explícita y no lo hace defina claramente el comportamiento unario ni en 6.5.3.3c1,3 ni en 6.5c4. En este último dice Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, ...) ... return values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.), que excluye el menos unario y las cosas parecen ser vagas.

This earlier question se refiere a la K & libro R ANSI C, sección A.7.4.5 que dice The negative of an unsigned quantity is computed by subtracting the promoted value from the largest value of the promoted type and adding one.

¿Cuál sería el estándar C de 1999 equivalente a la cita anterior del libro?

6.2.5c9 dice: A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

es que? ¿O hay algo más que me estoy perdiendo?

+1

Sí, es §6.2.5. –

+1

Los resultados de los operadores '<<' and '>>' no dependen de la representación de los enteros. Se definen como multiplicación y división por potencias de dos y solo están bien definidos solo para operandos no negativos. '<<' no está definido para los operandos negativos, y '>>' está definido por la implementación para los operandos negativos. –

+0

'El negativo de una cantidad sin firmar se calcula restando el valor promocionado del mayor valor del tipo promocionado y añadiendo uno' - Sé que mi kung fu matemático es débil en comparación con el poderoso Ritchie y Stroustrup, pero esto parece una Una forma pobre, y tal vez insensata, de manejar una situación que ciertamente es un error del programador 99.9 ...% de las veces. ¿Por qué no lanzar un error de compilación diciendo 'has intentado aplicar un signo a un tipo sin firmar, dingus'? – CCJ

Respuesta

14

Sí, 6.2.5c9 es exactamente el párrafo que buscaba.

+3

Alternativamente, uno podría ver el operador negativo como produciendo el inverso aditivo de su operando. Si N no está firmado, -N es equivalente a 1U + ~ N porque ese es el valor que, cuando se agrega a N, arrojará cero. – supercat

+0

@supercat Entonces, ¿tiene garantizado el comportamiento complementario de dos, incluso si el hardware subyacente usa una representación diferente de números negativos? – JAB

+0

@JAB: las representaciones de dos complementos coinciden con las representaciones sin firmar, pero la definición del comportamiento no tiene nada que ver con el complemento de dos. – supercat

4

En cada aplicación que conozco, un negativo se calcula como two's complement ...

int a = 12; 
int b = -a; 
int c = ~a + 1; 
assert(b == c); 

... así que en realidad no hay diferencia física entre los enteros sin signo y "negativas" firmados negativos - la única diferencia está en cómo están interpretados.

Así que en este ejemplo ...

unsigned a = 12; 
unsigned b = -a; 
int c = -a; 

... la bc y van a contener exactamente los mismos bits. La única diferencia es que b se interpreta como 2^32-12 (o 2^64-12), mientras que c se interpreta como "normal" -12.

Por lo tanto, un negativo se calcula de la misma manera independientemente de "signo", y el lanzamiento entre unsigned y signed es en realidad un no-op (y nunca puede causar un overflow en un sentido que algunos bits necesitan ser "cortado").

+8

Sé todo eso de la práctica también. La pregunta es sobre una cosa diferente, comportamiento según el estándar. –

+0

No sabía esto y parece ser algo fundamental, ta. +1 –

5

El comportamiento del operador unario negativo en operandos sin firmar no tiene nada que ver con si una máquina utiliza una aritmética de dos complementos con números con signo. En cambio, dado unsigned int x,y;, la instrucción y=-x; causará que y reciba el valor que tendría que mantener para que x+y sea igual a cero. Si x es cero, y también será cero. Para cualquier otro valor de x, será UINT_MAX-x+1, en cuyo caso el valor aritmético de x+y será UINT_MAX+1+(y-y) que, cuando se asigne a un unsigned integer, tendrá UINT_MAX+1 restado de él, produciendo cero.

Cuestiones relacionadas