2010-03-27 6 views
2

donc ce qui suit convertit grands Boutiens aux petitsBoutiens autochtones et conversion automatique

uint32_t ntoh32(uint32_t v) 
{ 
    return (v << 24) 
     | ((v & 0x0000ff00) << 8) 
     | ((v & 0x00ff0000) >> 8) 
     | (v >> 24); 
} 

travaux. comme un charme.

J'ai lu 4 octets à partir d'un gros fichier endian dans char v[4] et passer dans la fonction ci-dessus

ntoh32 (* reinterpret_cast<uint32_t *> (v)) 

qui ne fonctionne pas - parce que mon compilateur (VS 2005) convertit automatiquement le grand endian omble chevalier [4] dans un petit boutiste uint32_t quand je fais le casting.

AFAIK, cette conversion automatique ne sera pas portable, donc j'utiliser

uint32_t ntoh_4b(char v[]) 
{ 
    uint32_t a = 0; 
    a |= (unsigned char)v[0]; 
    a <<= 8; 
    a |= (unsigned char)v[1]; 
    a <<= 8; 
    a |= (unsigned char)v[2]; 
    a <<= 8; 
    a |= (unsigned char)v[3]; 
    return a; 
} 

oui le (unsigned char) est nécessaire. oui c'est chien lent.

il doit y avoir un meilleur moyen. n'importe qui ?

+0

Non, le compilateur du VC ne change pas le boutisme. Aucun autre compilateur non plus. Votre fichier de données peut ne pas avoir l'endianness que vous pensez qu'il fait. Et dire quelque chose est "chien lent" basé sur une hypothèse est une façon horrible d'optimiser. –

Répondre

2

La meilleure façon, à mon humble avis, utilise les fonctions htonl et ntohl. Si vous voulez être vraiment portable, vous ne pouvez pas penser en termes de "convertir en petit boutiste". Au contraire, vous devriez penser à "convertir en hôte endian". C'est ce que ntohl est pour, si votre entrée est un big-endian à coup sûr (qui est ce que le standard réseau est). Maintenant, si vous lisez vos octets individuellement, vous pouvez les lire comme un long non signé (en mode binaire) - cela devrait vous donner un long-boutiste, puis vous pouvez le convertir en ce dont vous avez besoin - si vous besoin d'hôte endian, puis ntohl.

+0

peut-être que vous n'avez pas compris ma question. l'implémentation de la méthode n'est pas le problème - la méthode * signature * est. – Manav

+0

@KnickerKicker: considérez mon deuxième paragraphe - soit lire les octets directement dans un long, ou les lire dans char [4] qui fait partie d'une union avec un long –

+0

Je vais essayer - ça devrait marcher.merci :) de toute façon, savez-vous pourquoi le compilateur fait cela, et tous les compilateurs le font – Manav

0

Chien lent? Avez-vous réellement le mesurer? Vous pouvez réécrire dans le style de ntoh32 et de réduire considérablement le nombre d'opérations:

uint32_t ntoh_4b(char v[]) 
{ 
    return ((uint32_t)(unsigned char)v[0] << 24) 
     | ((uint32_t)(unsigned char)v[1] << 16) 
     | ((uint32_t)(unsigned char)v[2] << 8) 
     | ((uint32_t)(unsigned char)v[3]  ); 
} 
+0

bien, j'ai juste supposé que ce sera :) Je vais essayer de les profiler plus tard - mais je pense que ce sera plus lent en raison de toute l'indexation de tableau ... - de toute façon, belle * réinterprétation * – Manav

+0

C'est un tableau char (sizeof == 1) avec des indices constants. Je parie que c'est rapide comme l'éclair, même sans l'optimisation du compilateur, mais en fait je ne m'en soucierais pas jusqu'à ce qu'il se révèle être un goulot d'étranglement. Votre version a une variable temporaire avec 8 accès en écriture et 8 en lecture, complètement manquante dans ma version. Ce que je voulais dire avec les opérations. – Secure

+0

voir les points de repère ci-dessous – Manav

0

(affichage cela comme une réponse distincte pour préserver indentation)

Le banc d'essai ...

union { 
     char a[4]; 
     uint32_t i; 
    } t; 
    t.i = 0xaabbccdd; 

    uint32_t v; 
    for (uint32_t i = 0; i < -1; ++i) 
    { 
     //v = ntohl (t.i); (1) 
     //v = ntoh32 (t.i); (2) 
     //v = ntoh_4b (t.a); (3) 
    } 

le démontage de ntoh32 ...

movl %edi, -4(%rbp) 
movl -4(%rbp), %eax 
movl %eax, %edx 
sall $24, %edx 
movl -4(%rbp), %eax 
andl $65280, %eax 
sall $8, %eax 
orl %eax, %edx 
movl -4(%rbp), %eax 
andl $16711680, %eax 
shrl $8, %eax 
orl %eax, %edx 
movl -4(%rbp), %eax 
shrl $24, %eax 
orl %edx, %eax 
leave 

le démontage de ntoh_4b ...

movq %rdi, -8(%rbp) 
movq -8(%rbp), %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
movl %eax, %edx 
sall $24, %edx 
movq -8(%rbp), %rax 
addq $1, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
sall $16, %eax 
orl %eax, %edx 
movq -8(%rbp), %rax 
addq $2, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
sall $8, %eax 
orl %eax, %edx 
movq -8(%rbp), %rax 
addq $3, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
orl %edx, %eax 
leave 

Et enfin, les résultats. J'ai inclus le temps pour la ntohl de bibliothèque C pour fournir une base pour comparision

//v = ntohl (t.i); (1) 
real 0m35.030s 
user 0m34.739s 
sys 0m0.245s 

//v = ntoh32 (t.i); (2) 
real 0m36.272s 
user 0m36.070s 
sys 0m0.115s 

//v = ntoh_4b (t.a); (3) 
real 0m40.162s 
user 0m40.013s 
sys 0m0.097s 
Questions connexes