es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Calcular el rango de tipos de variables en C.

Eres un traductor de español que traduce documentos de TI. Traduce lo siguiente al español. No traduzcas el código y los resultados en markdown

Aquí un aficionado, así que perdón por la pregunta sin experiencia. K&R ex. 2-1. Utilice las constantes del encabezado y/o el cálculo directo para calcular el rango de varios tipos de variables (char, short, int, long) + tipos en coma flotante. Usé las constantes limits.h para imprimir el rango de los tipos de variables de ancho fijo como referencia. Y todavía tengo que revisar IEEE754.

Mi función máx me da 1 menos para el resultado deseado, como: 0xfe, 0xfffe, etc., por lo que el LSB por alguna razón no cambia a 1. ¿Por qué es eso? Ayer, mientras pensaba en el problema, se me ocurrió la idea de usar el tipo void* para pasar los diversos tipos de variables a las funciones min-max. Para poder desreferenciar el tipo void* almacenando direcciones de números de ancho fijo con longitudes diferentes, tuve la idea de simplemente convertirlo al tipo size_t*, y de alguna manera funciona, y no sé por qué. ¿Es esto legal, nunca lo he visto en mis libros de programación en C? Si no es legal, ¿qué otras posibilidades hay de desreferenciar el tipo void*?

No deseo usar bucles y comprobar desbordamientos, ese método es muy lento.

#include <stdio.h> 
#include <float.h> 
#include <limits.h>

void unsigned_max(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;

    while(bit) {
        *(size_t*)data_ptr |= 1 << bit;
        bit--;
    }
}

void unsigned_min(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;

    while(bit){
        *(size_t*)data_ptr &= 0 << bit;
        bit--;
    }
}

void signed_min(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;
    *(size_t*)data_ptr |= 1 << bit;
    bit--;

    while (bit) {
        *(size_t*)data_ptr |= 0 << bit;
        bit--;
    }
}

void signed_max(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;
    *(size_t*)data_ptr &= 0 << bit;
    bit--;

    while (bit) {
        *(size_t*)data_ptr |= 1 << bit;
        bit--;
    }
}

int main(void) {

    unsigned char u_byte = 0;
    char byte = 0;
    unsigned short ushort_intgr = 0;
    short short_intgr = 0;
    unsigned int u_intgr = 0;
    int intgr = 0;
    unsigned long ulong_intgr = 0;
    long long_intgr = 0;

    char str_output[18] = "Min-max range of";
    char delimiter[18] =  "================";

    /*
    * Print ranges of unsigned and signed instances of char, short, int and long
    * variables using limits.h constants.
    */

    printf("%s unsigned char:\n%x,%x\n", str_output, u_byte, UCHAR_MAX);
    printf("%s signed char:\n%x,%x\n", str_output, CHAR_MIN, CHAR_MAX);
    printf("%s unsigned short:\n%x,%x\n", str_output, ushort_intgr, USHRT_MAX);
    printf("%s signed short:\n%x,%x\n", str_output, SHRT_MIN, SHRT_MAX);
    printf("%s unsigned int:\n%x,%x\n", str_output, u_intgr, UINT_MAX);
    printf("%s signed int:\n%x,%x\n", str_output, INT_MIN, INT_MAX);
    printf("%s unsigned long:\n%x,%x\n", str_output, ulong_intgr, ULONG_MAX);
    printf("%s signed long:\n%x,%x\n", str_output, LONG_MIN, LONG_MAX);

    printf("%s\n", delimiter);

    /*
    * Print ranges of unsigned and signed instances of char, short, int and long
    * variables using bitwise operations.
    */

    printf("%s unsigned char:\n%d,", str_output, u_byte);
    unsigned_max(&u_byte, sizeof(u_byte));
    printf("%x\n", u_byte);

    printf("%s signed char:\n", str_output);
    signed_min(&u_byte, sizeof(u_byte));
    printf("%x,", u_byte);
    signed_max(&u_byte, sizeof(u_byte));
    printf("%x\n", u_byte);

    printf("%s unsigned short:\n%d,", str_output, ushort_intgr);
    unsigned_max(&ushort_intgr, sizeof(ushort_intgr));
    printf("%x\n", ushort_intgr);

    printf("%s signed short:\n", str_output);
    signed_min(&short_intgr, sizeof(short_intgr));
    printf("%x,", short_intgr);
    signed_max(&short_intgr, sizeof(short_intgr));
    printf("%x\n", short_intgr);

    printf("%s unsigned int:\n%u,", str_output, u_intgr);
    unsigned_max(&u_intgr, sizeof(u_intgr));
    printf("%x\n", u_intgr);

    printf("%s signed int:\n", str_output);
    signed_min(&intgr, sizeof(intgr));
    printf("%x,", intgr);
    signed_max(&intgr, sizeof(intgr));
    printf("%x\n", intgr);

    printf("%s unsigned long:\n%lu,", str_output, ulong_intgr);
    unsigned_max(&ulong_intgr, sizeof(ulong_intgr));
    printf("%x\n", ulong_intgr);

    printf("%s signed long:\n", str_output);
    signed_min(&long_intgr, sizeof(long_intgr));
    printf("%x,", long_intgr);
    signed_max(&long_intgr, sizeof(long_intgr));
    printf("%x\n", long_intgr);

    return 0;
}

Mi resultado es:

Min-max range of unsigned char:
0,ff
Min-max range of signed char:
ffffff80,7f
Min-max range of unsigned short:
0,ffff
Min-max range of signed short:
ffff8000,7fff
Min-max range of unsigned int:
0,ffffffff
Min-max range of signed int:
80000000,7fffffff
Min-max range of unsigned long:
0,ffffffff
Min-max range of signed long:
80000000,7fffffff

Min-max range of unsigned char:
0,fe
Min-max range of signed char:
fe,7e
Min-max range of unsigned short:
0,fffe
Min-max range of signed short:
ffff8000,7ffe
Min-max range of unsigned int:
0,fffffffe
Min-max range of signed int:
80000000,7ffffffe
Min-max range of unsigned long:
0,fffffffe
Min-max range of signed long:
80000000,7ffffffe

También observé la solución del libro K&R, los escritores resuelven habitualmente todo con líneas elegantes. No parece funcionar cuando lo ejecuto, dando ceros para los valores mínimos y máximos. Sé que -0 es todo verdadero en forma de complemento a uno. ¿En ese momento, -0 se podría haber almacenado como 0x1111? Así que 0x1111 >> 1 = 0x0111; 0x0111*(-1) = 0x1000?

printf("signed char min = %d\n", -(char)((unsigned char) -0 >> 1));
printf("signed char max = %d\n", (char)((unsigned char) -0 >> 1));
printf("unsigned char max = %u\n", (unsigned char) -0);
...
</limits.h></float.h></stdio.h>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    En relación al problema con el LSB que no se está alternando en la función unsigned_max(), parece ser debido a la forma en que está utilizando el operador <<. Tiene una menor prioridad que los operadores & y |, por lo que es mejor usar paréntesis para asegurarse de que se ejecute primero:

    *(size_t*)data_ptr |= (1 << bit);
    

    En cuanto al uso de size_t* para desreferenciar punteros void*, generalmente no se recomienda, ya que puede presentar problemas de alineación y de orden de bytes. Una práctica común es utilizar una conversión de tipo a un tipo conocido antes de desreferenciar, como por ejemplo:

    int* int_ptr = (int*)data_ptr;
    int value = *int_ptr;
    

    Alternativamente, también se puede utilizar unión para convertir el puntero void* a un tipo específico:

    union {
        void* void_ptr;
        int* int_ptr;
    } data;
    
    data.void_ptr = data_ptr;
    int value = *data.int_ptr;
    

    Con respecto a la solución K&R, parece estar utilizando la representación de complemento a dos de enteros con signo, donde el bit más significativo se utiliza como bit de signo. La expresión -0 crea un valor con todos los bits establecidos en 1, que es la representación de complemento a dos del valor negativo más pequeño. Desplazándolo a la derecha en 1 crea el valor positivo más grande, y la conversión de tipo a char genera los valores correctos para el mínimo y el máximo. Sin embargo, esto puede no funcionar en todas las plataformas, por lo que sigue siendo mejor utilizar las constantes CHAR_MIN y CHAR_MAX definidas en limits.h.

Comments are closed.