OVH Cloud OVH Cloud

long & 64 bits

29 réponses
Avatar
alian
Ave,

J'ai un probleme avec cet algo de calcul de crc32 sur ia64:
long crc = 0xFFFFFFFF;
if (buf != NULL) {
while (len > 0) {
crc = (crc >> 8) ^ ((long) crc32tab[(crc ^ (*buf)) &
0xff]);
buf++;
len--;
}
}

Le (long) vient me mettre la grouille et j'ai aucune idee comment
corriger ca. Est ce que qqn a une idee ? Pis comme je suis une chiasse,
si je pouvais avoir l'explication theorique avec ... Parce que que je
me dise que le long fait 8 bits, ben ca me change pas grand chose ...

sur ia64:
./a.out TEST
O=EEEA93B8

sur i386:
./a.out TEST
O=11156C47

Voici le programme de test complet, a compiler avec juste g++
monfichier.c, a tester avec ./a.out monmot :

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <string>
#include <iostream>
using namespace std;

#define LIMITED_32(x) ((x) & 0xFFFFFFFF)

static const unsigned long crc32tab[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

long Signed_CRC32(const char *buf, size_t len) {
long crc = 0xFFFFFFFF;

if (buf != NULL) {
while (len > 0) {
crc = (crc >> 8) ^ ((long) crc32tab[(crc ^ (*buf)) &
0xff]);
buf++;
len--;
}
}

return LIMITED_32(~crc);
}

int main(int argc, char** argv)
{
std::string param(argv[1]);
long value = Signed_CRC32(param.c_str(), param.size());
printf("O=%lX\n", value);
}

10 réponses

1 2 3
Avatar
Blaise Potard
Antoine Leca wrote:
En news:,
alian va escriure:

J'ai un probleme avec cet algo de calcul de crc32 sur ia64:
long crc = 0xFFFFFFFF;



unsigned long, à tout le moins. Tu ne veux *pas* de propagation de signe...


Visiblement, ce code ne vient pas du PO, et je ne crois pas que le but
ici soit de discuter de la validité du calcul effectué, mais d'obtenir
les mêmes résultats qu'un algo existant, pour des soucis de
compatibilité. C'est sûr qu'avec des unsigned, tout devient plus simple!
Mais vu que la fonction s'appelle Signed_CRC32, j'imagine que le calcul
avec des machins signés est *volontaire*, même si c'est mal©.


Avatar
Alian
Visiblement, ce code ne vient pas du PO, et je ne crois pas que le but
ici soit de discuter de la validité du calcul effectué, mais d'obtenir
les mêmes résultats qu'un algo existant, pour des soucis de
compatibilité.


Vi !

C'est sûr qu'avec des unsigned, tout devient plus simple!
Mais vu que la fonction s'appelle Signed_CRC32, j'imagine que le calcul
avec des machins signés est *volontaire*, même si c'est mal©.


En fait la Unsigned_CRC32 fonctionne deja ... Et la Signed est la pour des
histoire de compatibilites avec une fonction PHP qui demande un signed ...
Brrrr. Il vaut mieux pas savoir. Ca a l'air treeees D'ailleurs cette
machine itanium s'appelle Vador, un hasard ?

Avatar
Vincent Lefevre
Dans l'article ,
Pierre Maurette écrit:

J'ai un probleme avec cet algo de calcul de crc32 sur ia64:
long crc = 0xFFFFFFFF;
if (buf != NULL) {
while (len > 0) {
crc = (crc >> 8) ^ ((long) crc32tab[(crc ^ (*buf)) &
0xff]);
buf++;
len--;
}
}

Le (long) vient me mettre la grouille et j'ai aucune idee comment
corriger ca. Est ce que qqn a une idee ? Pis comme je suis une chiasse,
si je pouvais avoir l'explication theorique avec ... Parce que que je
me dise que le long fait 8 bits, ben ca me change pas grand chose ...
A première vue, votre code n'est pas portable, en ce sens qu'il suppose

un long de 32 bits, sizeof(long)==4.


Déjà, le code est buggé avec des long de 32 bits.

Remplacez long par un type à taille fixe de 32 bits. A mon avis en
unsigned. S'il n'existe pas, vous le fabriquez, avec des #if, les
constantes de limits.h, et des typedef.


Ou unsigned long avec un masquage.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Antoine Leca
En news:e099kl$gb1$, Blaise Potard va escriure:
Antoine Leca wrote:
En news:,
alian va escriure:

J'ai un probleme avec cet algo de calcul de crc32 sur ia64:
long crc = 0xFFFFFFFF;


unsigned long, à tout le moins. Tu ne veux *pas* de propagation de
signe...


Visiblement, ce code ne vient pas du PO, et je ne crois pas que le but
ici soit de discuter de la validité du calcul effectué, mais d'obtenir
les mêmes résultats qu'un algo existant, pour des soucis de
compatibilité.


Certes. Cependant, il faut dire que lorsque le message commence par
::: algo de calcul de crc32
il est permis de se tromper et de supposer que le but de l'algorithme
(décrit nulle part) est de calculer « un CRC sur 32 bits ».
Au temps pour moi donc, comme je l'écrivais.

Après, par exemple en relisant le fil aujourd'hui, on comprend mieux ;
surtout lorsqu'on apprend que
::: En fait la Unsigned_CRC32 fonctionne deja ...
;-)


Pour en revenir à l'algorithme initial, il n'est pas portable tel quel en
dehors d'une machine 16 ou 32 bits en complément à 2 avec l'implémentation
classique de >> ; et la « solution » que vous avez trouvé pour résoudre ce
problème, est de rester bien tranquillement dans ce cadre bien sécurisant.

Mais est-ce la meilleure chose à faire ? Est-ce que Alian a compris pourquoi
cela fonctionnait (ce qui était un des buts du fil) ?


C'est sûr qu'avec des unsigned, tout devient plus simple!


Pas du tout. Cela devient plus *clair*, ou plus portable.
Par contre, je concède que les performances seront moins bonnes.


Qu'est-ce que donne (désolé, je n'ai pas de jeu d'essai) :

/* NON TESTÉ */

long Signed_CRC32(const unsigned char *tab, size_t lg) {
unsigned long long crc = 0xFFFFFFFF;

if(tab)
while(lg--) {
unsigned char indice=(crc ^ *tab++) & 0xFF;

crc >>= 8;
if(crc&0x00800000) crc|=0xFF000000; /* effet de signed >> */
crc ^= crc32tab[indice];
}

return crc^0xFFFFFFFF;
}


La ligne avec le commentaire représente la perte de performances pour ne
_pas_ utiliser les propriétés spécifiques de l'architecture (ici l'opération
sur des nombres négatifs). Le reste des changements n'est que du
comestique (ou des erreurs de ma part).



long long, c'est pour être bien sûr que l'on va utiliser des registres sur
64 bits, /donc/ être portable sur une architecture 64 bits.


Antoine



Avatar
Blaise Potard
Antoine Leca wrote:
Pour en revenir à l'algorithme initial, il n'est pas portable tel quel en
dehors d'une machine 16 ou 32 bits en complément à 2 avec l'implémentation
classique de >> ; et la « solution » que vous avez trouvé pour résoudre ce
problème, est de rester bien tranquillement dans ce cadre bien sécurisant.


C'était effectivement plus un vulgaire hack qu'autre chose.

C'est sûr qu'avec des unsigned, tout devient plus simple!



Pas du tout. Cela devient plus *clair*, ou plus portable.


Oui, je voulais dire qu'il était nettement plus facile d'avoir un
programme portable avec un calcul de crc sur des unsigned.

Par contre, je concède que les performances seront moins bonnes.


Qu'est-ce que donne (désolé, je n'ai pas de jeu d'essai) :


Ça marche, ça donne en 64-bits exactement le même résultat que la
version 32-bits.

/* NON TESTÉ */

long Signed_CRC32(const unsigned char *tab, size_t lg) {
unsigned long long crc = 0xFFFFFFFF;

if(tab)
while(lg--) {
unsigned char indice=(crc ^ *tab++) & 0xFF;

crc >>= 8;
if(crc&0x00800000) crc|=0xFF000000; /* effet de signed >> */
crc ^= crc32tab[indice];
}

return crc^0xFFFFFFFF;
}



Avatar
James Kanze
Antoine Leca wrote:
En news:,
Pierre Maurette va escriure:


J'ai un probleme avec cet algo de calcul de crc32 sur ia64:
long crc = 0xFFFFFFFF;
if (buf != NULL) {
while (len > 0) {
crc = (crc >> 8) ^ ((long) crc32tab[(crc ^ (*buf)) &
0xff]);
buf++;
len--;
}
}




A première vue, votre code n'est pas portable, en ce sens
qu'il suppose un long de 32 bits, sizeof(long)==4.



Où ?


crc >> 8

Si la taille d'un long est 32 bits, la valeur initiale de crc
est négative, et le résultat d'un >> sur une valeur négative
dépend de l'implémentation.

En règle générale, quand on manipule les bits comme ici, les
types unsigned sont préférables. Pour des choses comme les CRC,
j'utilise normalement uint32_t et al.

(Le même code, à peine corrigé, doit fonctionner avec
sizeof(long)==2, avec des char sur 16 bits, en supposant bien
sûr que les données de la trame ont été rangées un octet par
byte; mais là je suis d'accord que c'est pour faire joujou.)


Remplacez long par un type à taille fixe de 32 bits.



Et si tu n'en as pas ?


L'algorithme ici ne marche pas ? (En fait, je crois que les bits
supplémentaires de poids forts seront toujours 0, et que donc,
l'algorithme marchera quand même. Mais il y a des algorithmes
semblables où c'est moins évidents.)

A mon avis en unsigned.



Là oui, cela risque d'aider.


C'est même essentiel, je crois.

--
James Kanze
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



Avatar
James Kanze
Pierre Maurette wrote:
[...]
tu peux corriger un peu plus proprement en utilisant un cast
vers int32_t, ou alors tu peux déclarer ton tableau en
int32_t (ce qui te permet d'économiser un peu de place en
mémoire, de te débarasser du cast, et en plus c'est un peu
plus logique). Il faut probablement ajouter un #include
<inttypes.h>



inttypes.h, et plus précisément stdint.h, est C99. Donc, pas
C++, sauf à utiliser la bibliothèque Boost (cstdint.hpp).
Sinon, il faut donc soit utiliser des entiers à taille fixe
propres à l'implémentation, soit les fabriquer.


Sauf qu'ici, on parle justement du C, et non du C++. Et donc,
stdint.h est standard (et Boost risque de ne pas marcher du
tout).

--
James Kanze
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


Avatar
Pierre Maurette
Pierre Maurette wrote:
[...]
tu peux corriger un peu plus proprement en utilisant un cast
vers int32_t, ou alors tu peux déclarer ton tableau en
int32_t (ce qui te permet d'économiser un peu de place en
mémoire, de te débarasser du cast, et en plus c'est un peu
plus logique). Il faut probablement ajouter un #include
<inttypes.h>


inttypes.h, et plus précisément stdint.h, est C99. Donc, pas
C++, sauf à utiliser la bibliothèque Boost (cstdint.hpp).
Sinon, il faut donc soit utiliser des entiers à taille fixe
propres à l'implémentation, soit les fabriquer.


Sauf qu'ici, on parle justement du C, et non du C++. Et donc,
stdint.h est standard (et Boost risque de ne pas marcher du
tout).
La question posée était certes pertinente ici. Néanmoins le PO est en

C++ :

<CIT>
Voici le programme de test complet, a compiler avec juste g++
monfichier.c, a tester avec ./a.out monmot :

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <string>
#include <iostream>
using namespace std;

[snip]

int main(int argc, char** argv)
{
std::string param(argv[1]);
long value = Signed_CRC32(param.c_str(), param.size());
printf("O=%lXn", value);
}
</CIT>

--
Pierre Maurette



Avatar
Vincent Lefevre
Dans l'article <e0c457$3bp$,
James Kanze écrit:

Sauf qu'ici, on parle justement du C, et non du C++. Et donc,
stdint.h est standard (et Boost risque de ne pas marcher du
tout).


Sauf que rigoureusement, c'est <stdint.h> et non stdint.h; enfin, la
norme met les chevrons partout, sauf dans l'index, pour une raison
technique je suppose.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Vincent Lefevre
Dans l'article <e0bi8g$68s$,
Antoine Leca écrit:

Pas du tout. Cela devient plus *clair*, ou plus portable.
Par contre, je concède que les performances seront moins bonnes.



Qu'est-ce que donne (désolé, je n'ai pas de jeu d'essai) :

/* NON TESTÉ */

long Signed_CRC32(const unsigned char *tab, size_t lg) {
unsigned long long crc = 0xFFFFFFFF;

if(tab)
while(lg--) {
unsigned char indice=(crc ^ *tab++) & 0xFF;

crc >>= 8;
if(crc&0x00800000) crc|=0xFF000000; /* effet de signed >> */
crc ^= crc32tab[indice];
}

return crc^0xFFFFFFFF;
}


Si j'ai bien compris, tu peux retourner une valeur qui n'est pas
représentable dans un long. Il faudrait tester si c'est > LONG_MAX
et renvoyer la valeur négative correspondante si ce n'est pas le
cas.

long long, c'est pour être bien sûr que l'on va utiliser des registres sur
64 bits, /donc/ être portable sur une architecture 64 bits.


Je ne comprends pas pourquoi un unsigned long ne suffirait pas,
puisque le CRC reste sur 32 bits.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

1 2 3