OVH Cloud OVH Cloud

Extraire des char d'un DWORD

8 réponses
Avatar
Michael
Bonjour à tous,

soit le DWORD suivant:

DWORD fourCC = 1685288548, soit 0x64737664;

En le découpant en:

char a = 0x64;
char b = 0x73;
char c = 0x76;
char d = 0x64;

J'ai a = 'd', b = 'v' , c = 's' , d = 'd'

Seulement, comment "couper" le dword en 4 char ?

8 réponses

Avatar
Sylvain
Michael wrote on 11/09/2006 22:51:

soit le DWORD suivant:

DWORD fourCC = 1685288548, soit 0x64737664;

Seulement, comment "couper" le dword en 4 char ?


tu veux dire récupérer les valeurs des 4 bytes formant le DWORD ?

le plus simple est

DWORD fourCC = 0x64737664;
char a = (char)(fourCC >> 24);
char b = (char)(fourCC >> 16);
char c = (char)(fourCC >> 8);
char d = (char) fourCC;

une union peut aussi permettre d'accéder aux bytes mais sera
architecture dépendante (Intel vs "CPU comptant à l'endroit").

Sylvain.

--
typedef unsigned long DWORD;
donc pas de pb de propagation de signe.

Avatar
Michael
une union peut aussi permettre d'accéder aux bytes mais sera
architecture dépendante (Intel vs "CPU comptant à l'endroit").


Comment tu fais ça? Ca m'intéresse...

Avatar
Sylvain
Michael wrote on 11/09/2006 23:34:
une union peut aussi permettre d'accéder aux bytes mais sera
architecture dépendante (Intel vs "CPU comptant à l'endroit").


Comment tu fais ça? Ca m'intéresse...


je répète, ce n'est pas portable (selon le type de proc) et peut échouer
selon le niveau d'optimisation et/ou l'alignement des données:

// valable pour proc. big-endian
union composite {
DWORD int32;
struct {
char lo;
char m1;
char m2;
char hi;
};
};

int main(){
composite fourCC;
fourCC.int32 = 0x64737664;
char a = fourCC.hi;
char b = fourCC.m2;
char c = fourCC.m1;
char d = fourCC.lo;
}

Sylvain.


Avatar
loufoque

je répète, ce n'est pas portable (selon le type de proc) et peut échouer
selon le niveau d'optimisation et/ou l'alignement des données:


Sinon y'a aussi

uint32 foo = 0x64737664;
char* bar = reinterpret_cast<char*>(&foo);

Et si tu es en big-endian, tu te retrouves avec bar[0] == 0x64 etc.

Avatar
Sylvain
loufoque wrote on 12/09/2006 00:58:

Et si tu es en big-endian, tu te retrouves avec bar[0] == 0x64 etc.


en little-endian aussi !... bar[0] == bar[3] :)

Sylvain.

Avatar
Michael
// valable pour proc. big-endian
union composite {
DWORD int32;
struct {
char lo;
char m1;
char m2;
char hi;
};
};

int main(){
composite fourCC;
fourCC.int32 = 0x64737664;
char a = fourCC.hi;
char b = fourCC.m2;
char c = fourCC.m1;
char d = fourCC.lo;
}



Je ne comprends pas très bien comment fonctionne ce code.

Comment le compilo peut-il donner les bonnes valeurs à fourCC.hi, etc...

Est-ce parce que comme la structure et le DWORD partagent le même espace en
mémoire, du coup les 4 octets occupés par le DWORD se retrouvent être les
même 4 octets occupés par les membres de la structure?

Et concernant l'alignement des données, je suppose qu'il peut poser problème
dans le cas où le compilo déciderait que pour stocker l'union, il ne
choisirait pas 4 octets contigus?

Avatar
Sylvain
Michael wrote on 12/09/2006 01:34:

Je ne comprends pas très bien comment fonctionne ce code.

Comment le compilo peut-il donner les bonnes valeurs à fourCC.hi, etc...


dans le cas souhaité par celui qui code (le compilo peut avoir une autre
opinion) l'adresse de 'int32' est la même que celle de la struct
anonyme; donc affecter int32 affecte les 4 chars, inversement affecter
un des chars changerait l'octet de même adresse du long.

Est-ce parce que comme la structure et le DWORD partagent le même espace en
mémoire, du coup les 4 octets occupés par le DWORD se retrouvent être les
même 4 octets occupés par les membres de la structure?


oui.

Et concernant l'alignement des données, je suppose qu'il peut poser problème
dans le cas où le compilo déciderait que pour stocker l'union, il ne
choisirait pas 4 octets contigus?


oui, même si c'est peu probable, il alignera le champ suivant (y'en a
pas ici) selon cette valeur d'alignement mais la struct de 4 x 8 peut
rester comme cela ... ça dépends.

ça reste une mauvaise façon de faire pour les cas où l'on n'a pas droit
aux hypothèses (ie compilo, options diverses, non toutes maîtrisées).

il vaut mieux utiliser le mode verbieux de ma première réponse, ou si
vous voulez jouer avec les adresses et comme indiqué par loufoque:
char* ptr = (char*) &fourCC; puis lire ptr[i] (0<=i<4).

Sylvain.

Avatar
kanze
Michael wrote:

soit le DWORD suivant:

DWORD fourCC = 1685288548, soit 0x64737664;


DWORD est un typedef à un type entier ? (D'après le nom, d'au
moins 64 bits, ou ?)

En le découpant en:

char a = 0x64;
char b = 0x73;
char c = 0x76;
char d = 0x64;

J'ai a = 'd', b = 'v' , c = 's' , d = 'd'

Seulement, comment "couper" le dword en 4 char ?


Si j'ai bien compris, pour le caractère a, tu veux des bits 24 à
31. Donc :
a = (fourCC >> 24) & 0xFF ;

Tu fais pareil pour les autres caractères : à chaque fois, tu
définis grosso modo le bit de poids faible, et tu décales à
droite pour mettre ce bit dans le bit 0 ; ensuite, tu masques
avec le nombre de bits voulus. Donc, avec les valeurs que tu as
données, tu as des décalages de 24, de 16, de 8 et de 0 bits,
avec chaque fois une masque de 0x7F ou 0xFF (selon que tu
souhaites de l'ASCII, ou un autre encodage, genre ISO 8859-1).

En général, en revanche, il est préférable de ne pas passer par
là. S'il s'agit des caractères, on les stocke dans un
std::string, ou à la rigueur dans un char[]. (Ou dans un
std::wstring ou wchar_t[], pour des encodages qui l'exigent.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34