2016-02-26 1 views
3

Quelqu'un peut-il expliquer le code pour moi?Que se passe-t-il dans ce code?

Pourquoi 32 bits UINT? Pourquoi 0xff?

Que font 4 équipes droites ici?

int writeUINT32little(FILE *f, UINT32 i) 
{  
    int rc;  
    rc = fputc((i & 0xff), f);  
    if (rc == EOF)  return rc;  
    rc = fputc(((i >> 8) & 0xff), f);  
    if (rc == EOF)  return rc;  
    rc = fputc(((i >> 16) & 0xff), f);  
    if (rc == EOF)  return rc;  
    return fputc(((i >> 24) & 0xff), f); 
} 
+8

Cet écrit un entier non signé 32 bits dans le fichier au format petit-boutiste. –

+0

Erreur lors de la vérification d'une fonction qui écrit dans un fichier. Une découverte rare dans un monde où la vérification d'erreurs, même utile, est rarement vue. – user3386109

+0

Question de suivi (pour tout le monde): Pouvez-vous écrire un texte lisible * sans * en utilisant des commentaires? – TobiMcNamobi

Répondre

8

Cela prend un nombre entier de 32 bits non signé et les sorties dans un fichier, octet par octet avec l'octet le moins significatif en premier (à savoir petit-boutiste). Est la manière hexadécimale d'écrire 255 en décimal, ou 11111111 en binaire. Et & est la fonction bit à bit and. Mis ensemble, (i & 0xff) masque l'octet le moins significatif de l'entier.

Ensuite, les décalages décalent le tout sur 8 bits et le processus se répète pour imprimer l'octet suivant.

1

Qu'est-ce que cette fonction soi-disant fait est écrire un entier non signé 32bit à un flux de fichier dans little-endian. En réalité, au lieu de faire une petite tâche simple et de faire les choses correctement, il essaie de faire deux choses ensemble et de se tromper.

Avant d'entrer dans pourquoi cela est faux, je vais répondre rapidement à la question elle-même:

  • Pourquoi UINT32? Je ne sais pas C'est non standard et mieux être remplacé par uint32_t. Pourquoi le 0xff? Utilisé comme masque pour conserver les 8 bits inférieurs dans une variable plus grande (32 bits)
  • Que font 4 équipes droites ici? Les décalages sont utilisés pour amener chaque octet dans l'UINT original vers les bits les plus à droite dans l'ordre correct "little-endian".


Maintenant, avec cela de la route ...

Pourquoi est-ce mal?
Un char est garanti être at least 8 bits wide, mais pourrait être être plus grand. Cela signifie que fputc écrira probablement 8 bits par appel, mais il pourrait écrire plus. Ce que cela signifie est que sur une certaine architecture où un caractère est (par exemple) 16 bits, la fonction écrira 64 bits par appel et ce ne sera pas du tout little-endian. De plus, la fonction vérifie avec soin les erreurs mais n'expose pas les informations d'échec pertinentes à l'appelant (combien d'octets ont été écrits?).

Quoi de mieux?
Tout d'abord, comme toujours, faire une petite chose et le faire bien:

uint32_t toLittleEndian(uint32_t v) 
{ 
    uint32_t result = v >> 24; 
    result |= v << 24; 
    result |= (v >> 8) & 0xf0; 
    result |= (v << 8) & 0xf00; 
    return result; 
} 

Note: cette mise en œuvre est délibérément bavard.Il y a une possibilité d'optimisation en utilisant des opérations de rotation de bits, mais C n'a pas de support natif pour cela et nécessite un code d'assemblage

Cette fonction ne convertit un big-endian valeur 32 bits à sa représentation peu endian équivalente (en fait, il alterne entre les deux et pourrait être nommé switchEndian).

Ensuite, nous avons besoin d'écrire la valeur dans un fichier:

int write(uint32_t v, FILE *f) 
{ 
    return fwrite(&v, sizeof(v), 1, f); 
} 

Cela écrire exactement 32 bits de large entier, et retourne le nombre d'octets écrit. De plus, c'est réutilisable.

Ensuite, nous pourrions créer une fonction composite pratique si l'on veut:

int writeLittleEndian(uint32_t v, FILE *f) 
{ 
    return write(toLittleEndian(v), f); 
}