Signo Extendiendo un int en C

Así que estoy teniendo algunos problemas para obtener un campo de un int y luego firmarlo extendiéndolo. Tengo un método que obtiene el campo de un int.

getField(int value, int hi, int lo); 

Valor es el int del que estoy tomando un campo, y hi y lo es el tamaño del campo.

Así que puedo llamar a este método getField dentro de getFieldSignExtended (int value, int hi, int lo), pero ¿cómo hago para extender el signo?

eg value = 7, hi = 1, lo = 0

getField(7, 1, 0); devuelve 3 porque 7 en binario es 111 y hi y lo toman el campo de 0 a 1.

Con 3 devueltos desde getField obtengo que el valor es igual a 0x0003.

Lo que tengo hasta ahora funciona con aspectos positivos, pero confunde enormemente los aspectos negativos. Y cuando digo “desorden” quiero decir que no funciona en absoluto. Entonces, si trato de usarlo en -1, aparece como un int grande en lugar de negativo.

¡Gracias por cualquier ayuda! :]

Edit: Lo siento, me confundí a mí mismo y a algunos de ustedes con una statement contradictoria: P. Fijo.

Hay una gran cantidad de lecturas entre las líneas que están pasando aquí. Sin embargo, si getField(7, 1, 0) devuelve 3 y necesita getFieldSignExtended(15, 2, 0) para devolver -3 y getFieldSignExtended(3, 2, 0) para devolver +3 , entonces esto podría ser lo que está buscando. después.

El concepto es que usted trata un campo de n bits de los bits hi: lo del valor original como un número de complemento de 2. Si el primer bit de los n bits es un 1, entonces desea que el campo de n bits sea tratado como un número negativo. Si el primer bit del campo de 3 bits es un 0, entonces debe tratarse como un número positivo.

 #include  #include  #include  extern int getFieldSignExtended(int value, int hi, int lo); enum { INT_BITS = CHAR_BIT * sizeof(int) }; int getFieldSignExtended(int value, int hi, int lo) { assert(lo >= 0); assert(hi > lo); assert(hi < INT_BITS - 1); int bits = (value >> lo) & ((1 << (hi - lo + 1)) - 1); if (bits & (1 << (hi - lo))) return(bits | (~0U << (hi - lo))); else return(bits); } 

Las 3 afirmaciones son directas; el único controvertido es que el código se niega a tratar con el bit 31. Si lo invocó con hi = 31 y lo = 0, entonces el desplazamiento (hi - lo + 1) es demasiado grande y el comportamiento no está definido. También se encuentra con el comportamiento definido por la implementación de desplazar a la derecha un número negativo. Sería posible solucionar estos problemas tomando un argumento entero sin signo y no haciendo la operación & si hi - lo + 1 == INT_BITS . La solución de los problemas se deja como un ejercicio para el lector.

La asignación a bits cambia el valor a la derecha y lo enmascara con el número correcto de bits. El (1 << (hi - lo + 1)) - 1 desplaza 1 izquierda más que el número de bits en el campo, luego resta uno para generar una cadena de 1 binarios para cada posición de bit en el campo. Por ejemplo, para hi = 2, lo = 0, esto desplaza 1 izquierda 3 lugares, produce 1000 binarios; al restar 1 se obtiene 0111, por lo que se seleccionan los 3 bits correctos. Entonces, los bits contienen el conjunto apropiado de bits para el entero de n bits.

La prueba if comprueba si el bit más significativo del entero de n bits está establecido. Si el bit de signo no está establecido, simplemente devolvemos los bits valor. Si se establece el bit de signo, entonces tenemos que realizar un cálculo complicado, que fue (muy) incorrecto en el primer borrador de esta respuesta. Supongamos que tenemos un campo de 3 bits = 101. Como un número complementario de 2 bits 2, eso representa -3. Necesitamos extender eso a la izquierda con todos los 1 para generar el tamaño completo -1 . El valor de ~0 es todos los bits 1; cuando se desplaza hacia la izquierda por los bits hi - lo , deja una serie de ceros para los bits de no signo del valor. También funcionaría si cambiara a la izquierda con hi - lo + 1 , pero se necesita un cálculo adicional para el + 1 que no es necesario.

Utilicé este arnés de prueba para convencerme de que el código funcionaba correctamente. La salida de prueba sistemática es rigurosa (en números pequeños). Asegura que el valor calculado coincida con el valor esperado. La prueba 'exhaustiva' no es realmente exhaustiva; solo prueba un valor, y es más para observar problemas (como el uso de hi = 31 y lo = 0 da una respuesta errónea de 0 en mi máquina) y patrones.

 static const struct { int value; int hi; int lo; int wanted; } tests[] = { { 0x0F, 1, 0, -1 }, { 0x0F, 2, 0, -1 }, { 0x0F, 2, 1, -1 }, { 0x0F, 3, 1, -1 }, { 0x0F, 4, 2, +3 }, { 0x0F, 5, 0, +15 }, { 0x0F, 5, 1, +7 }, { 0x0F, 5, 2, +3 }, { 0x0F, 5, 3, +1 }, { 0x0F, 5, 4, 0 }, { 0x03, 2, 0, +3 }, { 0xF3, 2, 0, +3 }, { 0xF3, 3, 0, +3 }, { 0xF3, 4, 0, -13 }, { 0xF3, 5, 0, -13 }, { 0xF3, 6, 0, -13 }, { 0xF3, 7, 0, -13 }, { 0xF3, 7, 1, -7 }, { 0xF3, 7, 2, -4 }, { 0xF3, 7, 3, -2 }, { 0xF3, 7, 4, -1 }, { 0xF3, 8, 0, 0xF3 }, }; enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) }; static const char s_pass[] = "== PASS =="; static const char s_fail[] = "!! FAIL !!"; static void systematic_test(void) { int fail = 0; for (int i = 0; i < NUM_TESTS; i++) { char const *pf = s_fail; int actual = getFieldSignExtended(tests[i].value, tests[i].hi, tests[i].lo); if (actual == tests[i].wanted) pf = s_pass; else fail++; printf("%s GFSX(%+4d = 0x%.4X, %d, %d) = %+4d = 0x%.8X (wanted %+4d = 0x%.8X)\n", pf, tests[i].value, tests[i].value, tests[i].hi, tests[i].lo, actual, actual, tests[i].wanted, tests[i].wanted); } printf("%s\n", (fail == 0) ? s_pass : s_fail); } static void exhaustive_test(void) { int value = 0x5FA03CE7; for (int i = 1; i < INT_BITS - 1; i++) { for (int j = 0; j < i; j++) { int actual = getFieldSignExtended(value, i, j); printf("%11sGFSX(%d = 0x%X, %2d, %2d) = %+10d = 0x%.8X\n", "", value, value, i, j, actual, actual); } } } int main(void) { int result1 = getFieldSignExtended(15, 2, 0); int result2 = getFieldSignExtended( 3, 2, 0); printf("GFSX(15, 2, 0) = %+d = 0x%.8X\n", result1, result1); printf("GFSX( 3, 2, 0) = %+d = 0x%.8X\n", result2, result2); printf("\nSystematic test\n"); systematic_test(); printf("\nExhaustive test\n"); exhaustive_test(); return(0); } 

Esta es la salida del código de prueba antes de la prueba exhaustiva, más una pequeña selección de la salida de la prueba exhaustiva:

 GFSX(15, 2, 0) = -1 = 0xFFFFFFFF GFSX( 3, 2, 0) = +3 = 0x00000003 Systematic test == PASS == GFSX( +15 = 0x000F, 1, 0) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF) == PASS == GFSX( +15 = 0x000F, 2, 0) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF) == PASS == GFSX( +15 = 0x000F, 2, 1) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF) == PASS == GFSX( +15 = 0x000F, 3, 1) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF) == PASS == GFSX( +15 = 0x000F, 4, 2) = +3 = 0x00000003 (wanted +3 = 0x00000003) == PASS == GFSX( +15 = 0x000F, 5, 0) = +15 = 0x0000000F (wanted +15 = 0x0000000F) == PASS == GFSX( +15 = 0x000F, 5, 1) = +7 = 0x00000007 (wanted +7 = 0x00000007) == PASS == GFSX( +15 = 0x000F, 5, 2) = +3 = 0x00000003 (wanted +3 = 0x00000003) == PASS == GFSX( +15 = 0x000F, 5, 3) = +1 = 0x00000001 (wanted +1 = 0x00000001) == PASS == GFSX( +15 = 0x000F, 5, 4) = +0 = 0x00000000 (wanted +0 = 0x00000000) == PASS == GFSX( +3 = 0x0003, 2, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003) == PASS == GFSX(+243 = 0x00F3, 2, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003) == PASS == GFSX(+243 = 0x00F3, 3, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003) == PASS == GFSX(+243 = 0x00F3, 4, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3) == PASS == GFSX(+243 = 0x00F3, 5, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3) == PASS == GFSX(+243 = 0x00F3, 6, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3) == PASS == GFSX(+243 = 0x00F3, 7, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3) == PASS == GFSX(+243 = 0x00F3, 7, 1) = -7 = 0xFFFFFFF9 (wanted -7 = 0xFFFFFFF9) == PASS == GFSX(+243 = 0x00F3, 7, 2) = -4 = 0xFFFFFFFC (wanted -4 = 0xFFFFFFFC) == PASS == GFSX(+243 = 0x00F3, 7, 3) = -2 = 0xFFFFFFFE (wanted -2 = 0xFFFFFFFE) == PASS == GFSX(+243 = 0x00F3, 7, 4) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF) == PASS == GFSX(+243 = 0x00F3, 8, 0) = +243 = 0x000000F3 (wanted +243 = 0x000000F3) == PASS == Exhaustive test GFSX(1604336871 = 0x5FA03CE7, 1, 0) = -1 = 0xFFFFFFFF GFSX(1604336871 = 0x5FA03CE7, 2, 0) = -1 = 0xFFFFFFFF GFSX(1604336871 = 0x5FA03CE7, 2, 1) = -1 = 0xFFFFFFFF GFSX(1604336871 = 0x5FA03CE7, 3, 0) = +7 = 0x00000007 GFSX(1604336871 = 0x5FA03CE7, 3, 1) = +3 = 0x00000003 GFSX(1604336871 = 0x5FA03CE7, 3, 2) = +1 = 0x00000001 GFSX(1604336871 = 0x5FA03CE7, 4, 0) = +7 = 0x00000007 GFSX(1604336871 = 0x5FA03CE7, 4, 1) = +3 = 0x00000003 GFSX(1604336871 = 0x5FA03CE7, 4, 2) = +1 = 0x00000001 GFSX(1604336871 = 0x5FA03CE7, 4, 3) = +0 = 0x00000000 GFSX(1604336871 = 0x5FA03CE7, 5, 0) = -25 = 0xFFFFFFE7 GFSX(1604336871 = 0x5FA03CE7, 5, 1) = -13 = 0xFFFFFFF3 GFSX(1604336871 = 0x5FA03CE7, 5, 2) = -7 = 0xFFFFFFF9 GFSX(1604336871 = 0x5FA03CE7, 5, 3) = -4 = 0xFFFFFFFC GFSX(1604336871 = 0x5FA03CE7, 5, 4) = -2 = 0xFFFFFFFE GFSX(1604336871 = 0x5FA03CE7, 6, 0) = -25 = 0xFFFFFFE7 GFSX(1604336871 = 0x5FA03CE7, 6, 1) = -13 = 0xFFFFFFF3 GFSX(1604336871 = 0x5FA03CE7, 6, 2) = -7 = 0xFFFFFFF9 GFSX(1604336871 = 0x5FA03CE7, 6, 3) = -4 = 0xFFFFFFFC GFSX(1604336871 = 0x5FA03CE7, 6, 4) = -2 = 0xFFFFFFFE GFSX(1604336871 = 0x5FA03CE7, 6, 5) = -1 = 0xFFFFFFFF ... GFSX(1604336871 = 0x5FA03CE7, 29, 28) = +1 = 0x00000001 GFSX(1604336871 = 0x5FA03CE7, 30, 0) = -543146777 = 0xDFA03CE7 GFSX(1604336871 = 0x5FA03CE7, 30, 1) = -271573389 = 0xEFD01E73 GFSX(1604336871 = 0x5FA03CE7, 30, 2) = -135786695 = 0xF7E80F39 GFSX(1604336871 = 0x5FA03CE7, 30, 3) = -67893348 = 0xFBF4079C GFSX(1604336871 = 0x5FA03CE7, 30, 4) = -33946674 = 0xFDFA03CE GFSX(1604336871 = 0x5FA03CE7, 30, 5) = -16973337 = 0xFEFD01E7 GFSX(1604336871 = 0x5FA03CE7, 30, 6) = -8486669 = 0xFF7E80F3 GFSX(1604336871 = 0x5FA03CE7, 30, 7) = -4243335 = 0xFFBF4079 GFSX(1604336871 = 0x5FA03CE7, 30, 8) = -2121668 = 0xFFDFA03C GFSX(1604336871 = 0x5FA03CE7, 30, 9) = -1060834 = 0xFFEFD01E GFSX(1604336871 = 0x5FA03CE7, 30, 10) = -530417 = 0xFFF7E80F GFSX(1604336871 = 0x5FA03CE7, 30, 11) = -265209 = 0xFFFBF407 GFSX(1604336871 = 0x5FA03CE7, 30, 12) = -132605 = 0xFFFDFA03 GFSX(1604336871 = 0x5FA03CE7, 30, 13) = -66303 = 0xFFFEFD01 GFSX(1604336871 = 0x5FA03CE7, 30, 14) = -33152 = 0xFFFF7E80 GFSX(1604336871 = 0x5FA03CE7, 30, 15) = -16576 = 0xFFFFBF40 GFSX(1604336871 = 0x5FA03CE7, 30, 16) = -8288 = 0xFFFFDFA0 GFSX(1604336871 = 0x5FA03CE7, 30, 17) = -4144 = 0xFFFFEFD0 GFSX(1604336871 = 0x5FA03CE7, 30, 18) = -2072 = 0xFFFFF7E8 GFSX(1604336871 = 0x5FA03CE7, 30, 19) = -1036 = 0xFFFFFBF4 GFSX(1604336871 = 0x5FA03CE7, 30, 20) = -518 = 0xFFFFFDFA GFSX(1604336871 = 0x5FA03CE7, 30, 21) = -259 = 0xFFFFFEFD GFSX(1604336871 = 0x5FA03CE7, 30, 22) = -130 = 0xFFFFFF7E GFSX(1604336871 = 0x5FA03CE7, 30, 23) = -65 = 0xFFFFFFBF GFSX(1604336871 = 0x5FA03CE7, 30, 24) = -33 = 0xFFFFFFDF GFSX(1604336871 = 0x5FA03CE7, 30, 25) = -17 = 0xFFFFFFEF GFSX(1604336871 = 0x5FA03CE7, 30, 26) = -9 = 0xFFFFFFF7 GFSX(1604336871 = 0x5FA03CE7, 30, 27) = -5 = 0xFFFFFFFB GFSX(1604336871 = 0x5FA03CE7, 30, 28) = -3 = 0xFFFFFFFD GFSX(1604336871 = 0x5FA03CE7, 30, 29) = -2 = 0xFFFFFFFE 

Hay múltiples enfoques que puede tomar. Si estuviera comenzando, podría calcular aritméticamente el número de bits en el campo. Entonces, por ejemplo:

 if (value %2 >= 1) { // you know that the value has a `1` as the lest significant digit. // if that's one of the digits you're looking for, you can do something like count++ here } else { // least significant digit is a '0' } 

y entonces

 if (value % 4 >=2) { // you know that the second least significant digit is `1` // etc. } 

Si lo haces de esa manera, es probable que quieras trabajar en un bucle de algún tipo.

Ahora, una mejor manera de hacerlo es usar bitwise anding , como esto:

 if (value & 8 != 0) // here you know that the fourth least significant digit (the one representing 8) is 1. // do a Google search on bitwise anding to get more information.