Valor inesperado después del casting tipo en c

Estaba implementando el código para enviar datos a través de una toma en bruto. Como parte de eso, tengo que construir un paquete IP. Pero estoy enfrentando el problema como se explica a continuación utilizando un programa de muestra.

#include 

struct iph {
    unsigned char ihl:4;
    unsigned char ver:4;
    unsigned char data;
    unsigned char data1;
};

int main()
{
    char buff[3] = {0};

    struct iph *ptr = (struct iph *)buff;
    ptr->ihl = 5;
    ptr->ver = 4;
    ptr->data = 0xAB;
    ptr->data1 = 0xCD;

    printf("%x %x %x\n", buff[0], buff[1], buff[2]);
}

Aquí la salida que estoy esperando 45 ab cd Pero me estoy poniendo 45 ffffffab ffffffcd. ¿Puede alguien explicar cómo está sucediendo esto y compartir una solución para obtener el valor esperado?

Pregunta hecha hace 3 años, 5 meses, 0 días - Por compilercaptain


4 Respuestas:

  • char está firmado en su máquina y 0xab es un valor negativo para los tipos de datos firmados de 8 bits. Así que cuando se promueve, se promueve al mismo valor negativo y eso es 0xffffffab como un int.

    Solución: uso unsigned char

    Respondida el Dec 17, 2020 a las 10:05 - por stackscripter

    Votos positivos: 0 | Votos negativos: 0

  • Usted código tiene dos problemas, primero buff array tiene que ser 4 tamaño no 3, segundo su tipo de buff tiene que ser unsigned char.

    Respondida el Dec 17, 2020 a las 10:14 - por codechampionx

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando se debe al uso de campos de bits en la estructura iph. Los campos de bits en C pueden ser propensos a comportamientos no deseados y dependen de la implementación del compilador.

    Cuando asignas los valores 0xAB y 0xCD a ptr->data y ptr->data1 respectivamente, estos están siendo tratados como valores de tipo char (signed char por defecto). Como unsigned char es de 1 byte en tamaño, el rango de valores posibles va desde 0 a 255. En el caso de 0xAB y 0xCD, que son mayores a 127, estos se interpretan como números negativos cuando son asignados a char o unsigned char.

    Para corregir esto, puedes cambiar los campos data y data1 a unsigned char y asegurarte de que los valores asignados en ellos estén dentro del rango de 0 a 255.

    Aquí tienes el código modificado:

    c
    include 
    struct iph {
        unsigned char ihl:4;
        unsigned char ver:4;
        unsigned char data;
        unsigned char data1;
    };
    
    int main()
    {
        unsigned char buff[3] = {0};
    
        struct iph ptr = (struct iph )buff;
        ptr->ihl = 5;
        ptr->ver = 4;
        ptr->data = 0xAB;
        ptr->data1 = 0xCD;
    
        printf("%x %x %x\n", buff[0], buff[1], buff[2]);
    
        return 0;
    }
    

    Ahora, al declarar buff como unsigned char, el programa mostrará la salida esperada 45 ab cd.

    Respondida el Dec 18, 2020 a las 10:09 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El problema en el código es que estás asumiendo que los miembros de la estructura iph se almacenan en bytes contiguos en el búfer buff. Sin embargo, en la mayoría de las arquitecturas, los miembros de la estructura se almacenan según su alineación de datos, y los miembros más grandes (como data y data1) pueden ocupar varios bytes.

    En tu caso, los miembros ihl y ver son de 1 byte cada uno y se almacenan en el orden en que se declaran en la estructura. Sin embargo, los miembros data y data1 son de 1 byte cada uno y, según la alineación de datos de la arquitectura, pueden almacenarse en bytes diferentes.

    Para solucionar este problema, puedes utilizar la función memcpy() para copiar los datos de la estructura al búfer, asegurándote de alinearlos correctamente. Aquí tienes un código modificado:

    c
    include include 
    struct iph {
        unsigned char ihl:4;
        unsigned char ver:4;
        unsigned char data;
        unsigned char data1;
    };
    
    int main()
    {
        char buff[3] = {0};
    
        struct iph iph;
        iph.ihl = 5;
        iph.ver = 4;
        iph.data = 0xAB;
        iph.data1 = 0xCD;
    
        memcpy(buff, &iph, sizeof(iph));
    
        printf("%x %x %x\n", buff[0], buff[1], buff[2]);
    
        return 0;
    }
    

    Esta versión del código utiliza memcpy() para copiar toda la estructura iph al búfer buff, asegurándose de que los miembros se alineen correctamente. La salida del código ahora debería ser 45 ab cd, como se esperaba.

    Respondida el Dec 18, 2020 a las 10:16 - por Gemini

    Votos positivos: 0 | Votos negativos: 0