J'ai une structure comme ci-dessous:

struct myCoolStuff{
    uint32_t stuff1 :  4;
    uint32_t stuff2 :  4;
    uint32_t stuff3 : 24;
    uint32_t differentField;
}

Comment puis-je combiner ces champs dans un format hexadécimal pour l'impression à l'écran ou l'écriture dans un fichier? Je vous remercie.

struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233, .differentField=99};

printf("my combined stuff is: %x\n", <combined stuff>);
printf("My full field is: %x\n", data.differentField);

Expected Output: 
my combined stuff is: 0xFF66112233 
My different field is: 99
2
johnnyb 20 nov. 2018 à 18:38

4 réponses

Meilleure réponse

Premièrement, vous ne pouvez pas extraire 0xFF de 0xFF après l'avoir placé dans une variable 4 bits. 0xFF prend 8 bits. Idem pour 0x66.

En ce qui concerne la réinterprétation des champs de bits sous la forme d'un seul entier, vous pouvez, de manière très non portable (il y a des problèmes big-endian / little-endian et la possibilité de bourrer des bits) utilisez un union.

( Cette:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

struct myCoolStuff{
    union{
        struct {
        uint32_t stuff1 :  4;
        uint32_t stuff2 :  4;
        uint32_t stuff3 : 24;
        };
        uint32_t fullField;
    };
};
struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233};

int main()
{
    printf("My full field is: %" PRIX32 "\n", data.fullField);
}

Imprime 1122336F sur mon x86_64. )

Pour le faire portable , vous pouvez simplement prendre les champs de bits et les assembler manuellement:

Cette:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

struct myCoolStuff{
        uint32_t stuff1 :  4;
        uint32_t stuff2 :  4;
        uint32_t stuff3 : 24;
};
struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233};

int main()
{
    uint32_t fullfield = data.stuff1 << 28 | data.stuff2 << 24 | data.stuff3;
    printf("My full field is: %" PRIX32 "\n", fullfield);
}

Devrait imprimer F6112233 partout où il se compile (uint32_t n'est pas garanti d'exister (bien que sur les plates-formes POSIX, il le sera); uint_least32_t aurait été plus portable.)

Veillez à vous assurer que data.stuff1 a suffisamment de bits pour être déplaçable par 28. Le vôtre fait parce qu'il est tapé uint32_t, mais il serait plus sûr de le faire par exemple, avec (data.stuff1 + 0UL)<<28 ou (data.stuff1 + UINT32_C(0))<<28 et même pour le deuxième quart de travail.

3
PSkocik 20 nov. 2018 à 16:11

Multipliez (en utilisant au moins uint32_t maths) puis imprimez en utilisant le spécificateur correspondant.

#include <inttypes.h>

struct myCoolStuff{
    uint32_t stuff1 :  4;
    uint32_t stuff2 :  4;
    uint32_t stuff3 : 24;
    uint32_t differentField;
}

uint32_t combined stuff = ((uint32_t) data.stuff1 << (4 + 24)) | 
    ((uint32_t) data.stuff2 <<  24) |  data.stuff3;

printf("my combined stuff is: 0x%" PRIX32 "\n", combined stuff);
printf("My full field is: %x\n", data.differentField);
1
chux - Reinstate Monica 20 nov. 2018 à 16:11

Peut-être que quelque chose comme ça aidera:

unsigned char *ptr = (unsigned char *)&data; // store start address
int size = sizeof(myCoolStuff); // get size of struct in bytes
while(size--) // for each byte
{
    unsigned char c = *ptr++; // get byte value
    printf(" %x ", (unsigned)c); // print byte value
}
0
Bogdan N. 20 nov. 2018 à 15:46

Ajoutez une union à l'intérieur de cette structure que vous pouvez utiliser pour réinterpréter les champs.

struct myCoolStuff{
    union {
        struct {
            uint32_t stuff1 :  4;
            uint32_t stuff2 :  4;
            uint32_t stuff3 : 24;
        };
        uint32_t stuff;
    }
    uint32_t fullField;
};

...

printf("my combined stuff is: %x\n", data.stuff);
1
dbush 20 nov. 2018 à 15:42