2009-12-13 8 views
0

J'ai du code C que je voudrais porter sur Java. Je n'ai pas fait beaucoup de codage C, mais j'ai été capable de suivre jusqu'à ce que cette fonction fonctionne. Si quelqu'un pouvait m'aider à comprendre ce qui se passe, ce serait grandement apprécié.Portage du code C; besoin d'aide avec l'opération au niveau du bit et la syntaxe du pointeur

int reverse_integer(int input) { 
    int output = 0, i; 

    for (i=0, i<sizeof(int); i++) { 
     output = (input & 0x000000FF) | output; 
     input >>= 8; 
     if (i < 3) { 
      output <<= 8; 
     } 
    } 

    return output; 
} 

Cette fonction est utilisée en tant que telle:

char * position = //some data 

/*the included comment on this next line states its the size of a string*/ 
int i = reverse_integer(*(int*)position) 
+3

Est-ce que cela compile? Le pour n'est pas pour (;;), mais pour (,;) xD. – webdreamer

+0

... désolé. mean (;;) – bigben

Répondre

7

Je serai ravi de publier un code Java qui fasse la même chose que le code C, mais seulement si vous promettez de ne pas l'utiliser.

/** Reverses the bytes in an integer. */ 
    public static int reverseInteger(int input) { 
     return 
     (input >>> 24) | 
     (input >> 8) & 0x0000ff00 | 
     (input << 8) & 0x00ff0000 | 
     (input << 24); 
    }

Notez qu'il n'y a pas de point de mise en boucle - un int en Java est toujours 4 octets. Notez également le triple angle droit au début de l'expression pour effectuer un décalage vers la droite non signé.

Maintenant, pour les raisons de ne pas l'utiliser:

1 - La fonction existe déjà - voir Integer.reverseBytes(int)

2 - Vous allez avoir du mal à utiliser ce code d'exemple, depuis Java n » t vous permet de lancer un tableau d'octets comme toute autre chose. Java est officiellement big-endian (octet le plus significatif en premier), donc si vous lisez des octets à partir d'un fichier, vous pouvez utiliser java.io.DataInputStream pour extraire des entiers, longs, etc.

+1

+1 pour mentionner Integer.reverseBytes (int) – Gunslinger47

5

Il est d'inverser l'ordre des octets (le endianness) d'un entier.

Il semble également y avoir un bug où le programmeur utilise 3, en supposant qu'il sera sizeof(int) - 1.

+1

+1, c'est le cas, mais n'est-ce pas la façon bizarre d'échanger des octets? ;-) –

+0

En fait, le 3 se prémunit contre la création d'une valeur de résultat plus large que quatre octets. Il place le quatrième et chaque octet haut supplémentaire dans l'octet le moins significatif de l'entier de résultat. Il devrait probablement juste être libéré si 'sizeof (int)' est supérieur à quatre, compte tenu de son traitement généralement irresponsable de cette situation. – seh

+0

seh, et faites cela au moment de la compilation. mais c'est bizarre de faire ça avec des changements de bit, de toute façon. –

1

La fonction inverse l'ordre des octets, comme nécessaire lors de la conversion entre les données big endian et little little endian. La plupart des protocoles réseau requis Les entiers 32 bits sont stockés dans l'ordre Big Endian, mais les processeurs Intel stockent les numéros dans l'ordre Little Endian. Vous devez donc permuter les ordres d'octets lors de la lecture ou de l'écriture des données sur le réseau. (Cela s'applique aux bas niveaux, pas pour les protocoles comme HTTP où les nombres sont transmis en tant que texte.)

Je crois que la fonction se compilerait en Java normal, à l'exception de sizeof(int), que vous pourriez remplacer par 4 depuis le JVM définit int comme ayant une largeur de 32 bits (en C, il n'y a aucune garantie).

Il semble que position est un bloc de données binaires, pas une chaîne. Le type de position est char *, ce qui signifie un pointeur sur un caractère (1 octet).

L'expression *position déréférencerait ce pointeur, obtenant le 1 octet vers lequel il pointe. Cependant, l'auteur du code voulait une valeur entière d'octets du bloc de données. (4 octets si compilé pour une 32 bits l'architecture; 8 octets pour ordinateur 64 bits.)

Donc, pour obtenir l'int plein, le pointeur est coulé à partir d'un pointeur d'octets à un pointeur d'int: (int *)position. Ensuite, parce que nous voulons la valeur à cette adresse, nous plaçons un astérisque à l'avant pour la déréférencer: *(int *)position.

1

[trop grand pour un commentaire] Si vous mettez le output <<= 8 au début de la boucle, vous pouvez éviter un if:

#include <limits.h> 
int reverse_integer(int input) { 
    int output = 0, i; 

    for (i = 0; i < sizeof input; i++) { 
     output <<= CHAR_BIT; 
     output = (input & ((1 << CHAR_BIT) - 1)) | output; 
     input >>= CHAR_BIT; 
    } 
    return output; 
} 

Cette fonction inverse les octets dans un int. Une entrée de 0x12345678, dans une implémentation où CHAR_BIT est 8 et sizeof (int) est 4 (le plus habituel de nos jours), renvoie 0x78563412.

2

Il existe un problème très sérieux avec cette fonction: résoudre un problème standard avec des solutions disponibles. Bref, il réinvente la roue.

Eh bien, je fais une hypothèse ici. Je suppose que la raison de l'inversion de l'entier est de convertir du little-endian au big-endian ou vice versa. La raison habituelle en est que vous êtes sur un ordinateur little-endian (toute puce Intel ou AMD x86) et que vous devez envoyer des données de réception de minerai à partir d'un réseau en "ordre réseau", c'est-à-dire big-endian.

Si je ne me trompe pas dans mon hypothèse, en C, vous pouvez appeler l'un:

ntohl() 
hlton() 

Plus d'informations sur ces fonctions ici:

http://www.codeguru.com/forum/showthread.php?t=298741

Si vous êtes déjà sur un grand ordinateur -endian, et vous voulez inverser l'entier pour une autre raison, alors ces appels ne vous aideront pas (parce que "commande réseau" est big-endian, donc si vous êtes déjà sur un gros-boutiste, hlton() ne changera rien).

J'ai fait une recherche Google pour "Java ntohl" et nous avons constaté ces liens:

http://www.velocityreviews.com/forums/t139571-ntohl-ntohs-etc.html

http://www.coderanch.com/t/366549/Java-General/java/Java-equivilent-c-functions-htonl

Alors, je pense que vous ne pouvez pas besoin au port du tout; vous pouvez peut-être simplement prendre une solution à partir de l'un de ces deux liens.

+1

Oui, mais 'ntohl()' et 'htonl()' sont des fonctions POSIX, non définies par le standard C - ie toutes les implémentations (de la norme C) les avoir. – pmg

+0

Assez juste. Mais même si vous êtes sur un système non-GCC qui n'en possède pas, Google peut probablement vous trouver une bibliothèque gratuite que vous pouvez utiliser. De même, en Java, quelqu'un a déjà résolu ce problème; et en fait l'un des liens que j'ai fournis a débogué du code à la fin de celui-ci et l'autre a une référence à 'java.nio.ByteBuffer'. C'est l'un des problèmes les plus courants, comme le tri. Et si vous utilisez un code déjà écrit, déjà débogué, vous n'avez pas besoin de le déboguer. – steveha

+0

Bien que, si vous utilisez du code déjà écrit, vous * devriez * le tester et vous assurer qu'il fait ce qu'il promet (et que vous comprenez comment l'utiliser correctement). – steveha

0

nous proposons le code suivant à octet ints d'échange:

U16 
Swap16 
(
    U16 x 
) 
{ 
    return (0xFF00 & x) >> 8 | (0x00FF & x) << 8; 
} 


U32 
Swap32 
(
    U32 x 
) 
{ 
#if defined(__i386__) 
    __asm__("bswap %0" : "+r" (x)); 
    return x; 
#else 
    return (0xFF000000 & x) >> 24 | 
      (0x00FF0000 & x) >> 8 | 
      (0x0000FF00 & x) << 8 | 
      (0x000000FF & x) << 24; 
#endif 
} 


U64 
Swap64 
(
    U64 x 
) 
{ 
#if defined(__i386__) 
    __asm__("bswap %%eax\n\t" 
      "bswap %%edx\n\t" 
      "xchgl %%eax, %%edx" : "+A" (x)); 
    return x; 
#elif defined(__x86_64__) 
    __asm__("bswap %0" : "+r" (x)); 
    return x; 
#else 
    return (0xFF00000000000000LL & 
      x) >> 56 | (0x00FF000000000000LL & x) >> 40 
      | (0x0000FF0000000000LL & 
       x) >> 24 | (0x000000FF00000000LL & x) >> 8 
      | (0x00000000FF000000LL & 
       x) << 8 | (0x0000000000FF0000LL & x) << 24 
      | (0x000000000000FF00LL & 
       x) << 40 | (0x00000000000000FFLL & x) << 56; 
#endif 
} 

Lorsque U16, U32 et U64 en tant que types entiers de cette taille.

L'asm est pour gcc.