2010-02-24 4 views
2

J'essaye d'échanger des octets pour une affectation, et j'ai pensé que ce serait la façon de le faire. P pointe vers l'objet scalaire à inverser size est le nombre d'octets de l'objet.Échange d'octets en C (endianness)

void *ReverseEndian(void *p, size_t size) 
{ 
    char *head = (char *)&p; 
    char *tail = head + size - 1; 

    for (; tail > head; --tail, ++head) { 
     char temp = *head; 
     *head = *tail; 
     *tail = temp; 
    } 
    return p; 
} 

Y a-t-il quelque chose qui ne va pas de soi? Je reçois une erreur avec mon code de test du professeur:

#define TestIt(a, b) TestReverse((void *)&(a),\ 
        ReverseEndian((void *)&(b), sizeof(b)), sizeof(b)) 


int main() 
char ch = 0x01, ch1 = ch; 
    short sh = 0x0123, sh1 = sh; 
    long lo = 0x, lo1 = lo; 
    float fl = 1234.567e27F, fl1 = fl; 
    double db = 123456.567890, db1 = db; 
    long double ld = 987654.321053e-204L, ld1 = ld; 
    void *vp = (void *)0x0123, *vp1 = vp; 
    char *cp = (char *)0x4567, *cp1 = cp; 
    char *ip = (char *)0x89AB, *ip1 = ip; 

    TestIt(ch1, ch); 
    TestIt(sh1, sh); 
    TestIt(lo1, lo); 
    TestIt(fl1, fl); 
    TestIt(db1, db); 
    TestIt(ld1, ld); 
    TestIt(vp1, vp); 
    TestIt(cp1, cp); 
    TestIt(ip1, ip); 

    printf("ReverseEndian succeeded!\n"); 

    return EXIT_SUCCESS; 
} 

void TestReverse(const void *before, const void *after, size_t size) 
{ 
    const char *cpBfore = (const char *)before; 
    const char *cpAfter = (const char *)after; 
    const char *tail; 

    for (tail = cpBfore + (size - 1); size; --size) 
     if (*tail-- != *cpAfter++) 
     { 
     fprintf(stderr, "ReverseEndian failed!\n"); 
     exit(EXIT_FAILURE); 
     } 
} 
+0

Le type de '& p;' dans '' ReverseEndian' est vide ** ', et vous êtes l'assigner à un 'char *', pourquoi? Qu'est-ce que ça veut dire?En C, vous ne devriez pas avoir besoin de lancer la plupart du temps, et si vous utilisez un casting, vous devez exactement savoir pourquoi (faire en sorte que le compilateur ne m'avertit pas n'est pas une raison). –

+0

Je pensais qu'un caractère est garanti à un octet. J'ai donc pensé que vous pouviez pointer vers le premier octet avec un pointeur sur char, puis échanger les octets de cette façon. – Crystal

Répondre

4

Ici

char *head = (char *)&p; 

vous définissez un pointeur qui pointe vers un autre pointeur. Donc vous avez un pointeur -> pointeur -> octets qui n'est évidemment pas ce que vous voulez. Heureusement, le programme ne s'est pas écrasé.

Il doit être char *head = (char *)p; afin que chaque octet soit lu à partir de la mémoire pointée par p.

+0

Mais je veux lire dans les octets. J'essaie d'échanger les octets individuels. Donc, n'est pas char * head = (char *) & p correct? – Crystal

+0

@Crystal: qu'est-ce que 'p', et où pointe-t-il? À quoi voulez-vous que la «tête» pointe? –

+0

De cette façon, vous permuteriez les octets de l'adresse à 'p'. Lorsque vous utilisez la bonne solution '(char *) p', vous pouvez écrire dans les octets (pointés par p) comme' * head = somevalue; ', comme vous le faites déjà. Assurez-vous de bien comprendre le concept des pointeurs! – AndiDog

1

char *head = (char *)&p devrait être char *head = (char *)p

2

p est une variable de pointeur (c.-à-une variable qui est titulaire d'une adresse mémoire de quelque chose), et dans la ligne suivante:

char *head = (char *)&p; 

... vous utilisez &p, qui vous donne l'adresse de la variable de pointeur elle-même, plutôt que la valeur d'adresse de mémoire que la variable pointeur contient (pointe vers).

Vouliez-vous dire à faire à la place?

char *head = (char *)p; 

Par ailleurs, votre code source semble inverser l'ordre d'une chaîne entière, par exemple "Bonjour" -> "olleH" (sauf si je le lis mal)

Ce n'est pas la même chose que l'inversion endianness. Le terme endian fait généralement référence à une valeur multi-octets qui est stockée avec l'octet le plus ou le moins significatif en premier.

A titre d'exemple, la valeur décimale 43981 est exprimée en hexadécimal sous la forme ABCD. Dans big-endian, l'octet le plus significatif (AB) serait stocké dans l'emplacement de mémoire inférieur et l'octet le moins significatif (CD) serait stocké dans l'emplacement de mémoire supérieur.

Dans little-endian, l'ordre est inversé; moins significatif suivi de plus significatif: CDAB.

+0

Pourquoi ne pas inverser une chaîne de la même manière que l'endianness? En quoi une chaîne de 4 caractères est-elle différente d'un int de 32 bits, en ce qui concerne l'échange d'endianness? – tomlogic

+1

@tomlogic - Endianness est l'ordre des sous-unités adressables individuellement (mots, octets ou même bits) dans un mot de données plus long. Par exemple, étant donné les valeurs suivantes de 16 bits '0x1122, 0x3344, 0x5566, 0x7788', la représentation little-endian ressemblerait à' 22 11 44 ​​33 66 55 88 77', alors que l'inversion des octets ressemblerait à '88 77 66 55 44 33 22 11'. –

+0

l'ai eu. Je supposais que la fonction ne serait utilisée que pour une seule valeur (p points pour l'objet scalaire à inverser, taille est le nombre d'octets de l'objet) auquel cas c'est une routine généralisée pour gérer un 16 bits, 32 bits ou un type intégral 64 bits. +1 pour une bonne clarification. – tomlogic

0

Vous ne devriez pas prendre l'adresse de p

Cela devrait fonctionner:

void *ReverseEndian(void *p, size_t size) 
{ 
    char *head = (char *)p; // here 
    char *tail = head + size - 1; 

    for (; tail > head; --tail, ++head) { 
     char temp = *head; 
     *head = *tail; 
     *tail = temp; 
    } 
    return p; 
}