Donc faisant suite à ce qui était dit ici, nous allons examiner le code suivant :
Je vais détailler pour les non-programmeurs, les autres auront sûrement déjà compris les grandes lignes en regardant le code.
Comme l'indique les commentaires le but est d'inverser l'ordre d'un groupe de quatre octets. Le premier devient le dernier, le deuxième l'avant dernier, etc... Le fait que ce soit pour des groupes de quatre octets est d'ailleurs mentionné en majuscules pour ne pas le louper.
Nous voyons donc la fonction qui fait l'inversion : rev_byte_order4, et deux autres qui l'utilisent. L'une nommée bswapi pour BytesSWAPInteger, l'autre bswapf pour BytesSWAPFloat.
Un œil averti vois déjà une source potentielle de problème avec bswapi : cette fonction prend en entrée un pointeur vers un int (c'est à dire un numéro de case mémoire qui nous indique où est le début du nombre entier dont on veut inverser les octets). Le hic est qu'un entier ( int ) n'est pas garanti comme faisant quatre octets de long, cela dépend de la machine pour laquelle le code aura été compilé. Dans le cas des MAC et PC ça sera ok mais ce n'est pas une bonne habitude que de ne pas contrôler la taille de ses variables, c'est la porte ouverte à des problèmes pas forcément simple à dépister.
La suite est également peu banale :
1 - bswapi crée un tableau local (local = qui n'existe que localement soit dans bswapi dans ce cas.) nommé tmpb et d'une taille de quatre octets ( char tmpb[4]; ).
2 - Dans ce tableau sont ensuite copiés les quatre octets formant l'entier que l'on souhaite inverser ( memcpy(tmpb, pint, 4); ).
3 - Le contenu de ce tableau est passé à rev_byte_order4 pour être inversé ( rev_byte_order4(tmpb); ).
4 - Le contenu du tableau, maintenant inversé, est copié dans notre entier d'origine ( memcpy(pint, tmpb, 4); ).
Ce n'est pas que ça ne fonctionne pas, c'est que c'est une sacré machine de Rube Goldberg pour simplement inverser quatre octets.
Récapitulons :
Ce que l'on veut faire :
1 - Recevoir un entier à inverser.
2 - L'inverser.
Ce que l'on a fait, cas favorable où l'appel de la fonction memcpy est optimisé par le compilateur et donc supprimé :
1 - On crée un tableau de quatre octets.
2 - L'entier à inverser est copiée dans ce tableau.
3 - L'entier dans le tableau est inversé.
4 - L'entier inversé dans le tableau est copié dans l'entier d'origine.
Ce que l'on a fait, cas défavorable où l'appel de la fonction memcpy n'est pas supprimé :
1 - On crée un tableau de quatre octets.
2 - On appelle memcpy pour copier l'entier à inverser dans ce tableau.
3 - memcpy copie ce qu'on lui dit de copier.
4 - L'entier dans le tableau est inversé.
5 - On appelle memcpy pour copier l'entier inversé du tableau vers l'entier d'origine.
6 - memcpy copie ce qu'on lui dit de copier.
Il est facile de se rendre compte que bswapf fait exactement la même chose, la seule différence étant qu'elle inverse un flottant au lieu d'un entier.
Les questions que tout cela soulève :
1 - Pourquoi aller copier pour inverser la copie et ensuite recopier la copie inversée à l'endroit même ou se trouve ce que l'on voulait inverser en premier lieu ?
2 - Pourquoi ne pas directement inverser ce foutu put..n d'entier directement là où il se trouve puisque c'est là qu'on veut mettre le résultat ?
3 - En supposant qu'il y ai une utilité à faire ces copies, pourquoi aller risquer qu'un memcpy soit appelé pour QUATRE octets alors qu'il est extrêmement facile de copier QUATRE octets par d'autres moyens qui prennnent beaucoup moins de temps qu'un appel à memcpy ? Un memcpy pour 1024 octets je veux bien, mais QUATRE ? Comme on dit en anglais : WTF
Cela vous semble un cas extrême ? Vous n'avez pas idée de ce que j'ai pu trouver dans tout le code que j'ai vu
. Je laisse l'examen de rev_byte_order4 pour demain.
PhM
Code:
// reverse byte-order for least/most signifigant-byte-first,
// which is done differently on Mac and IBM...
// This works as long as both platforms are IEEE, and
// the values passed in are FOUR BYTES (32 bits)... this
// includes FLOATS and LONGS, NOT SHORTS OR DOUBLEsS
void rev_byte_order4(char* retval)
{
char* add = retval;
char b1 = *(add);
add++;
char b2 = *(add);
add++;
char b3 = *(add);
add++;
char b4 = *(add);
add = retval;
*add = b4;
add++;
*add = b3;
add++;
*add = b2;
add++;
*add = b1;
}
void bswapi(int *pint)
{
char tmpb[4];
memcpy(tmpb, pint, 4);
rev_byte_order4(tmpb);
memcpy(pint, tmpb, 4);
}
void bswapf(float *pf)
{
char tmpb[4];
memcpy(tmpb, pf, 4);
rev_byte_order4(tmpb);
memcpy(pf, tmpb, 4);
}
Comme l'indique les commentaires le but est d'inverser l'ordre d'un groupe de quatre octets. Le premier devient le dernier, le deuxième l'avant dernier, etc... Le fait que ce soit pour des groupes de quatre octets est d'ailleurs mentionné en majuscules pour ne pas le louper.
Nous voyons donc la fonction qui fait l'inversion : rev_byte_order4, et deux autres qui l'utilisent. L'une nommée bswapi pour BytesSWAPInteger, l'autre bswapf pour BytesSWAPFloat.
Un œil averti vois déjà une source potentielle de problème avec bswapi : cette fonction prend en entrée un pointeur vers un int (c'est à dire un numéro de case mémoire qui nous indique où est le début du nombre entier dont on veut inverser les octets). Le hic est qu'un entier ( int ) n'est pas garanti comme faisant quatre octets de long, cela dépend de la machine pour laquelle le code aura été compilé. Dans le cas des MAC et PC ça sera ok mais ce n'est pas une bonne habitude que de ne pas contrôler la taille de ses variables, c'est la porte ouverte à des problèmes pas forcément simple à dépister.
La suite est également peu banale :
1 - bswapi crée un tableau local (local = qui n'existe que localement soit dans bswapi dans ce cas.) nommé tmpb et d'une taille de quatre octets ( char tmpb[4]; ).
2 - Dans ce tableau sont ensuite copiés les quatre octets formant l'entier que l'on souhaite inverser ( memcpy(tmpb, pint, 4); ).
3 - Le contenu de ce tableau est passé à rev_byte_order4 pour être inversé ( rev_byte_order4(tmpb); ).
4 - Le contenu du tableau, maintenant inversé, est copié dans notre entier d'origine ( memcpy(pint, tmpb, 4); ).
Ce n'est pas que ça ne fonctionne pas, c'est que c'est une sacré machine de Rube Goldberg pour simplement inverser quatre octets.
Récapitulons :
Ce que l'on veut faire :
1 - Recevoir un entier à inverser.
2 - L'inverser.
Ce que l'on a fait, cas favorable où l'appel de la fonction memcpy est optimisé par le compilateur et donc supprimé :
1 - On crée un tableau de quatre octets.
2 - L'entier à inverser est copiée dans ce tableau.
3 - L'entier dans le tableau est inversé.
4 - L'entier inversé dans le tableau est copié dans l'entier d'origine.
Ce que l'on a fait, cas défavorable où l'appel de la fonction memcpy n'est pas supprimé :
1 - On crée un tableau de quatre octets.
2 - On appelle memcpy pour copier l'entier à inverser dans ce tableau.
3 - memcpy copie ce qu'on lui dit de copier.
4 - L'entier dans le tableau est inversé.
5 - On appelle memcpy pour copier l'entier inversé du tableau vers l'entier d'origine.
6 - memcpy copie ce qu'on lui dit de copier.
Il est facile de se rendre compte que bswapf fait exactement la même chose, la seule différence étant qu'elle inverse un flottant au lieu d'un entier.
Les questions que tout cela soulève :
1 - Pourquoi aller copier pour inverser la copie et ensuite recopier la copie inversée à l'endroit même ou se trouve ce que l'on voulait inverser en premier lieu ?
2 - Pourquoi ne pas directement inverser ce foutu put..n d'entier directement là où il se trouve puisque c'est là qu'on veut mettre le résultat ?
3 - En supposant qu'il y ai une utilité à faire ces copies, pourquoi aller risquer qu'un memcpy soit appelé pour QUATRE octets alors qu'il est extrêmement facile de copier QUATRE octets par d'autres moyens qui prennnent beaucoup moins de temps qu'un appel à memcpy ? Un memcpy pour 1024 octets je veux bien, mais QUATRE ? Comme on dit en anglais : WTF
Cela vous semble un cas extrême ? Vous n'avez pas idée de ce que j'ai pu trouver dans tout le code que j'ai vu
. Je laisse l'examen de rev_byte_order4 pour demain.PhM



Commentaire