54 votes

Chaînes ASCII et endianness

Un stagiaire qui travaille avec moi m'a montré un examen qu'il avait passé en informatique sur les problèmes d'endianness. Il y avait une question qui montrait une chaîne ASCII "My-Pizza", et l'étudiant devait montrer comment cette chaîne serait représentée en mémoire sur un ordinateur en little endian. Bien sûr, cela ressemble à une question piège car les chaînes ASCII ne sont pas affectées par les problèmes d'endianness.

Mais choquant, le stagiaire affirme que son professeur insiste sur le fait que la chaîne serait représentée comme suit :

P-yM azzi

Je sais que ça ne peut pas être correct. Il n'y a aucune manière qu'une chaîne ASCII soit représentée de cette manière sur une machine. Mais apparemment, le professeur insiste là-dessus. Alors, j'ai rédigé un petit programme en C et j'ai dit au stagiaire de le donner à son professeur.

#include 
#include 

int main()
{
    const char* s = "My-Pizza";
    size_t length = strlen(s);
    for (const char* it = s; it < s + length; ++it) {
        printf("%p : %c\n", it, *it);
    }
}

Ceci démontre clairement que la chaîne est stockée comme "My-Pizza" en mémoire. Un jour plus tard, le stagiaire revient vers moi et me dit que le professeur prétend maintenant que le C convertit automatiquement les adresses pour afficher la chaîne dans le bon ordre.

Je lui ai dit que son professeur est fou, et que c'est clairement faux. Mais juste pour vérifier ma propre santé mentale, j'ai décidé de poster ceci sur stackoverflow pour que d'autres confirment ce que je dis.

Donc, je demande : qui a raison ici ?

0 votes

Avez-vous accès à un débogueur pour montrer au professeur? Est-ce Linux ou Windows?

0 votes

Bien sûr. La même chose pourrait être démontrée en utilisant gdb sur Linux, en examinant chaque octet en mémoire

4 votes

Pas besoin d'un débogueur : l'utilisation bien jouée de l'OP du spécificateur de format %p vous dit tout ce que vous avez vraiment besoin de savoir.

35voto

Heath Hunnicutt Points 9801

Sans aucun doute, vous avez raison.

La norme ANSI C 6.1.4 spécifie que les littéraux de chaîne sont stockés en mémoire en "concaténant" les caractères du littéral.

La norme ANSI 6.3.6 spécifie également l'effet de l'addition sur une valeur de pointeur:

Lorsqu'une expression de type entier est ajoutée à un pointeur ou soustraite d'un pointeur, le résultat a le type de l'opérande de pointeur. Si l'opérande de pointeur pointe vers un élément d'un objet tableau, et que le tableau est suffisamment grand, le résultat pointe vers un élément décalé par rapport à l'élément d'origine de telle sorte que la différence des souscripteurs des éléments de tableau résultants et originaux soit égale à l'expression entière.

Si l'idée attribuée à cette personne était correcte, alors le compilateur devrait également jongler avec les mathématiques entières lorsque les entiers sont utilisés comme indices de tableau. De nombreuses autres erreurs en résulteraient également qui sont laissées à l'imagination.

La personne peut être confuse, car (contrairement à un initialisateur de chaîne), des constantes de caractères multioctets telles que 'ABCD' sont stockées dans l'ordre des octets.

Il existe de nombreuses raisons pour lesquelles une personne pourrait être confuse à ce sujet. Comme d'autres l'ont suggéré ici, il pourrait mal interpréter ce qu'il voit dans une fenêtre de débogage, où les contenus ont été inversés par octets pour la lisibilité des valeurs entières.

12 votes

Il se peut que le professeur regarde la mémoire dans son débogueur en mode 32 bits et soit confus à cause de l'endianness?

0 votes

Il s'agit simplement d'un malentendu dû au fait que si peu de personnes ont vu un véritable dépôt et au fait que personne ici ne semble reconnaître qu'il faut écrire mille comme 1 000, pas 000,1. Cette réponse totalement fausse a reçu 8 votes de lecteurs tout aussi confus...

1 votes

@DigitalRoss. Écoute, Ross, je n'apprécie pas ton commentaire. Je lis des données depuis 29 ans à ce stade. Ma réponse est totalement correcte. Témoin de ce fait est ton incapacité à expliquer quoi que ce soit en sens inverse. Ou: s'il te plaît, explique-toi.

16voto

AndreyT Points 139512

Le professeur est confus. Pour voir quelque chose comme 'P-yM azzi', vous devez utiliser un outil d'inspection de mémoire qui affiche la mémoire en mode 'entier sur 4 octets' et en même temps vous donne une "interprétation de caractères" de chaque entier en mode de l'octet le plus significatif à l'octet le moins significatif.

Cela n'a bien sûr rien à voir avec la chaîne elle-même. Et dire que la chaîne elle-même est représentée de cette manière sur une machine little-endian est absurde.

0 votes

OK, @AndreyT, je pense que j'ai besoin de ton aide sur ce coup. Comme d'habitude, tu as raison, mais est-ce que cela pourrait être : c'est exactement ce que le prof voulait dire? J'ai le sentiment que la foule SO s'est dirigée dans la mauvaise direction sur ce coup...

6 votes

Hmm ... Peut-être, mais quelle serait la réponse "correcte" dans ce cas? Si l'on inspecte la mémoire en little-endian comme une séquence d'octets, on verrait 'My-Pizza' dedans. Si l'on l'interprète comme une séquence d'entiers sur 2 octets, ce serait 'yM P- zi az'. Dans le cas d'entiers sur 4 octets, c'est 'P-yM azzi'. Et enfin une interprétation en entiers sur 8 octets donnerait 'azziP-yM'. Toutes ces "interprétations" ne sont que cela - des interprétations, des moyens de afficher des données en mémoire. Toutes sont "correctes", une fois que l'on comprend d'où elles viennent. Rien ne donne au professeur la base de insister sur une seule d'entre elles comme étant la "bonne".

2 votes

Il a très peu de sens pour un débogueur de dire "Cet entier, s'il était stocké sur une machine avec une endianness différente, représenterait cette chaîne différente en mémoire".

12voto

caf Points 114951

Vous pouvez assez facilement prouver que le compilateur ne réalise pas de telles transformations "magiques" en effectuant l'impression dans une fonction qui ne sait pas qu'elle a reçu une chaîne de caractères :

int foo(const void *mem, int n)
{
    const char *cptr, *end;
    for (cptr = mem, end = cptr + n; cptr < end; cptr++)
        printf("%p : %c\n", cptr, *cptr);
}

int main()
{
    const char* s = "Ma-Pizza";

    foo(s, strlen(s));
    foo(s + 1, strlen(s) - 1);
}

Alternativement, vous pouvez même compiler en langage d'assemblage avec gcc -S et déterminer de manière concluante l'absence de magie.

6 votes

+1 pour ASM. De plus, vous pouvez écrire cette routine EN langage d'assemblage juste pour le prouver.

1 votes

+1 pour l'assemblage, je suis retourné et j'ai fait un lien vers cette réponse de stackoverflow.com/questions/1565567/…

10voto

Dmitry Brant Points 2567

Le professeur a tort si l'on parle d'un système qui utilise 8 bits par caractère.

Je travaille souvent avec des systèmes embarqués qui utilisent effectivement des caractères de 16 bits, chaque mot étant en little-endian. Sur un tel système, la chaîne "My-Pizza" serait effectivement stockée comme "yMP-ziaz".

Mais tant que c'est un système de 8 bits par caractère, la chaîne sera toujours stockée comme "My-Pizza" indépendamment de l'endianness de l'architecture de niveau supérieur.

1 votes

+1 Heath, j'ai fait beaucoup de travail embarqué et je n'ai jamais vu quelque chose de bizarre comme ça.

3 votes

Un produit sur lequel j'ai travaillé utilise un DSP de Texas Instruments (2808, je pense), dont l'unité de mémoire adressable la plus petite est de 16 bits.

0 votes

Aha, tous les paris sont off lorsque l'on parle de DSP. Comment écririez-vous le programme de l'OP avec seulement 16 bits d'adressage? Devez-vous décomposer les morceaux de 16 bits en morceaux de 8 bits vous-même?

2voto

Michael Buen Points 20453

Mais de manière choquante, le stagiaire affirme que son professeur insiste sur le fait que la chaîne serait représentée comme suit :

P-yM azzi

Elle serait représentée comme, représentée comme quoi ? représentée pour l'utilisateur en tant que dump d'entier 32 bits ? ou représentée/mise en forme dans la mémoire de l'ordinateur comme P-yM azzi ?

Si le professeur a dit que "My-Pizza" serait représenté/mis en forme comme "P-yM azzi" dans la mémoire de l'ordinateur parce que l'ordinateur est de l'architecture little endian, quelqu'un, s'il vous plaît, doit apprendre à ce professeur à utiliser un débogueur ! Je pense que c'est là que toutes les confusions du professeur découlent, j'ai comme l'intuition que le professeur n'est pas un codeur (non pas que je méprise le professeur), je pense qu'il n'a pas de moyen de prouver en code ce qu'il a appris sur l'endianness.

Peut-être que le professeur a appris les choses sur l'endianness il y a environ une semaine, puis il a simplement utilisé un débogueur incorrectement, rapidement ravi de son nouvel aperçu unique sur les ordinateurs, pour ensuite le prêcher immédiatement à ses étudiants.

Si le professeur a dit que l'endianness de la machine a une incidence sur la façon dont les chaînes ASCII seraient représentées en mémoire, il doit se remettre en question, quelqu'un devrait le corriger.

Si le professeur avait donné un exemple sur la façon dont les entiers sont représentés/mis en forme dans les machines différemment en fonction de l'endianness de la machine, ses étudiants pourraient apprécier ce qu'il enseigne à ce sujet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X