2 votes

C++ Décomposer un DWORD en caractères

J'ai un DWORD de quatre octets que je dois diviser en quatre caractères différents. Je pensais savoir comment faire, mais j'obtiens des chiffres bizarres à chaque fois. Voici mon code :

    // The color memory
    int32 col = color_mem[i];

    // The four destination characters
    char r, g, b, a;

    // Copy them in advancing by one byte every time
    memcpy(&r, &col, 1);
    memcpy(&g, &col + 1, 1);
    memcpy(&b, &col + 2, 1);
    memcpy(&a, &col + 3, 1);

10voto

pb2q Points 28514

Abandonnez le memcpy et utiliser la manipulation des bits :

r = (col & 0x000000ff);
g = (col & 0x0000ff00) >>  8;
b = (col & 0x00ff0000) >> 16;
a = (col & 0xff000000) >> 24;

ff dans les nombres hexadécimaux représente un octet de tous les éléments suivants 1 bits. Ceci et le & - AND par bit - rendra les octets qui ne vous intéressent pas - à chaque position - 0 et gardez les parties qui vous intéressent.

Le site >> décale les zéros depuis la gauche, plaçant l'octet que nous voulons dans la position la plus significative, pour l'affectation réelle. Un décalage de 8 décale d'une largeur d'un octet, 16 de deux octets et 24 de trois octets.

Visuellement, en regardant ff vous pouvez imaginer qu'on déplace les indices des octets vers la gauche.

4voto

Monroe Thomas Points 4674

Lorsque vous effectuez une arithmétique de pointeur, le montant de l'incrément ou du décrément est multiplié par la taille du type pointé. Lancer le int32 pointeur vers un char afin d'accéder à char à un certain décalage par rapport à l'adresse de base du fichier col .

Cette technique peut être fragile en raison des différences d'endian-ness sur les différentes plates-formes, je recommande donc d'utiliser les opérations bitmask plus portables fournies dans une autre réponse.

// The color memory  
int32 col = color_mem[i];  

// The four destination characters  
char r, g, b, a;  

// Copy them in advancing by one byte every time  
memcpy(&r, (char*)&col, 1);  
memcpy(&g, ((char*)&col) + 1, 1);  
memcpy(&b, ((char*)&col) + 2, 1);  
memcpy(&a, ((char*)&col) + 3, 1);

2voto

Etherealone Points 1289

Ajouter +1 à un int32 fera monter l'adresse de 4 octets.

Vous pourriez utiliser memcpy(&g, reinterpret_cast<char *>(&col)+1, 1) et ainsi de suite.

C'est mieux :

int32 col = color_mem[i];

struct splitted4byte
{
    char r;
    char g;
    char b;
    char a;
}

splitted4byte rgb;

memcpy(&rgb, &col, 4);

Vous devez vous préoccuper de l'ordre des octets dans le fichier col d'ailleurs. Je ne sais pas quelle partie de l'int32 correspond à quelle couleur.

Vous devriez vous renseigner sur l'endianness. (google le, il y a des documentations)

Lorsque la valeur la plus élevée de R et les autres couleurs sont 0, si elle est stockée en tant que 1111 1111 0000 0000 0000 0000 0000 0000 Je veux dire si la représentation entière de la couleur RGBA(255,0,0,0) est égale à cette valeur binaire. Elle sera ordonnée en sens inverse dans la mémoire, c'est-à-dire 0000 0000 0000 0000 0000 0000 1111 1111 Vous devez donc le calculer.

Vous pouvez utiliser des fonctions de conversion réseau qui convertissent l'ordre des octets du réseau (big-endian) en ordre des octets de la machine hôte (little endian ou encore big endian). De cette façon, vous n'aurez pas besoin de modifier votre code en fonction de la machine. (la fonction est ntohl (network to host long), il y a aussi htons (host to network short) et autres pour 2-byte, il y a aussi be64toh() pour les entiers 64-bit, mais la fonction n'existe que sur les variantes Unix si je me souviens bien). Tout ce que vous aurez à faire est int32 col = ntohl(color_mem[i]);

Vous pouvez aussi faire en sorte que votre structure soit ordonnée de la sorte, mais votre code ne fonctionnera pas en big-endian.

1voto

Gir Points 718

Puisque col est un int32 +1 ajoute un décalage de 4 octets

recherchez arithmétique des pointeurs sur google

1voto

paddy Points 26183

Chacun a donné des réponses différentes, et toutes sont correctes d'une manière ou d'une autre. Certaines sont spécifiques à l'endienne (comme pour les opérations par bit). D'autres ne le sont pas. Pour plus de clarté, je pourrais faire ceci :

char *bytes = (char*)&color_mem[i];
char r = bytes[0];
char g = bytes[1];
char b = bytes[2];
char a = bytes[3];

Je ne vois pas de raison d'utiliser memcpy . Même avec les structures. L'affectation des structures est une caractéristique du langage - vous n'êtes pas obligé de la copier.

Je n'ai pas encore vu de mention des syndicats...

union Pixel {
    DWORD packed;
    struct Components {
        char r, g, b, a;
    };
    char bytes[4];
};

// You can just specify your image data like this...
Pixel *pixels = (Pixel*)color_mem;

// Reference one pixel for convenience - don't need to reference, you can
// just copy it instead if you want (alternative: Pixel p = pixels[i])
Pixel &p = pixels[i];

char r = p.r;
char g = p.g;
char b = p.b;
char a = p.a;

int32 col = p.packed;

C'est indépendant de l'endienne : Il ne dépend pas de l'organisation d'un entier. En général, cela ne pose pas de problème, mais il faut quand même en être conscient.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X