106 votes

Ce code source active une chaîne en C. Comment fait-il cela?

Je lis un code d'émulateur et j'ai contré quelque chose de vraiment étrange:

 switch (reg){
    case 'eax':
    /* and so on*/
}
 

Comment est-ce possible? Je pensais que vous ne pouviez que switch sur les types intégraux. Y a-t-il une supercherie macro?

147voto

Bathsheba Points 23209

(Vous seul pouvez répondre à la macro "supercherie" part - à moins que vous collez en place plus de code. Mais il n'y a pas beaucoup de choses ici pour les macros de travailler sur - officiellement, vous n'êtes pas autorisé à redéfinir les mots clés; le comportement est indéfini.)

Afin de réaliser le programme de lisibilité, l'esprit de développeur est en train d'exploiter de mise en œuvre de comportement défini. 'eax' est pas une chaîne, mais un multi-caractère constant. Remarque très soigneusement les guillemets simples personnages autour d' eax. Le plus probable, c'est de vous donner un int dans votre cas, c'est unique à cette combinaison de caractères. (Assez souvent, chaque caractère occupe 8 bits en 32 bits int). Et tout le monde vous connaît peut - switch sur int!

Enfin, une norme de référence:

Le standard C99 dit:

6.4.4.4p10: "La valeur d'un nombre entier de caractères constante contenant plus d'un caractère (par exemple, "ab"), ou contenant un caractère ou séquence d'échappement qui ne sont pas associées à un seul octet d'exécution de caractères, la mise en œuvre est définie."

45voto

Vlad from Moscow Points 36219

Selon la Norme (6.8.4.2 L'instruction switch)

3 L'expression de chaque cas, l'étiquette doit être une constante entière expression...

et (6.6 expressions Constantes)

6 Une constante entière expression doit avoir de type entier et seulement des opérandes qui sont des constantes entières, le dénombrement des constantes, les constantes de caractère, sizeof expressions dont les résultats sont des constantes entières, et les constantes flottantes qui sont les opérandes de jette. Opérateurs de Cast dans une constante entière expression ne convertir arithmétique types de types integer, sauf dans le cadre d'un opérande de l'opérateur sizeof.

Maintenant, qu'est - 'eax'?

Le C Standard (6.4.4.4 constantes de Caractères)

2 Un entier de caractères constante est une séquence d'un ou de plusieurs multi-octets caractères entre guillemets simples, comme dans "x"...

Donc, 'eax' est un entier de caractères constante selon le paragraphe 10 de la même section

  1. ...La valeur d'un nombre entier de caractères constante contenant plus d'un caractère (par exemple, "ab"), ou contenant un caractère ou d'échapper à des séquence qui n'a pas la carte d'un seul octet d'exécution de caractère, est la mise en œuvre définies.

Ainsi, selon la première citation, il peut être un opérande d'une constante entière expression qui peut être utilisée comme un label.

Payer attention à ce que l'un caractère constant (entre guillemets simples) qui a pour type int et n'est pas le même comme une chaîne littérale (une séquence de caractères entre guillemets) qui a un type d'un tableau de caractères.

12voto

Stig Hemmer Points 2175

Comme d'autres l'ont dit, c'est un int constante et sa valeur réelle est mise en œuvre définies.

Je suppose que le reste du code ressemble à quelque chose comme

if (SOMETHING)
    reg='eax';
...
switch (reg){
    case 'eax':
    /* and so on*/
}

Vous pouvez être sûr que " eax "dans la première partie a la même valeur que" eax " dans la deuxième partie, de sorte que tout cela fonctionne, non? ... mal.

Dans un commentaire de @Davislor quelques listes de valeurs possibles pour 'eax':

... 0x65, 0x656178, 0x65617800, 0x786165, 0x6165, ou quelque chose d'autre

Avis de la première valeur potentielle? C'est juste 'e', en ignorant les deux autres personnages. Le problème est que le programme utilise probablement 'eax', 'ebx', et ainsi de suite. Si toutes ces constantes ont la même valeur que 'e' vous vous retrouvez avec

switch (reg){
    case 'e':
       ...
    case 'e':
       ...
    ...
}

Cela n'a pas l'air trop bon, n'est ce pas?

La bonne partie de la mise en œuvre "défini", c'est que le programmeur peut vérifier la documentation de leur compilateur et voir si il fait quelque chose d'intelligent avec ces constantes. Si elle le fait, à la maison gratuitement.

La mauvaise partie est que certains autres pauvre diable peut prendre le code et essayer de le compiler en utilisant un autre compilateur. Instant erreur de compilation. Le programme n'est pas portable.

Comme @zwol souligné dans les commentaires, la situation n'est pas tout à fait aussi mauvais que je pensais que, dans les mauvais cas, le code ne se compile pas. Cela permettra au moins de vous donner un nom exact du fichier et le numéro de ligne pour le problème. Encore, vous n'aurez pas un programme de travail.

2voto

chqrlie Points 17105

Le fragment de code utilise une bizarrerie historique appelé multi-caractère caractère constant, aussi appelé multi-caractères.

'eax' est un entier constant dont la valeur est définie par l'implémentation.

Voici une page intéressante sur multi-chars et comment ils peuvent être utilisés, mais ne doit pas:

http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html


En regardant en arrière plus loin dans le rétroviseur, voici comment l'original C manuel par Dennis Ritchie depuis le bon vieux temps ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) spécifié de caractères constantes.

2.3.2 les constantes de Caractère

Une constante de caractère est 1 ou 2 caractères entre guillemets simples ‘ ' ". Au sein d'une constante de caractère d'une seule citation doit être précédée par un anti-slash ‘\". Certains non-caractères graphiques, et ‘\" lui-même, peut-être échappé, selon le tableau suivant:

    BS \b
    NL \n
    CR \r
    HT \t
    ddd \ddd
    \ \\

L'évasion ‘\ddd" se compose de la barre oblique suivie par 1, 2, ou 3 octale qui sont prises afin de fixer la valeur du caractère souhaité. Un cas particulier de cette construction est ‘\0" (pas suivie par un chiffre) qui indique un caractère nul.

Les constantes de caractère se comportent exactement comme des entiers (pas, en particulier, comme des objets de type caractère). En conformité avec l'adressage de la structure de la PDP-11, une constante de caractère de longueur 1 est le code pour le personnage de la faible octet de poids fort et 0 dans l'octet de poids fort; une constante de caractère de longueur 2 est le code du premier caractère dans l'octet de poids faible et que, pour la deuxième personnage dans l'octet de poids fort. Les constantes de caractère avec plus d'un caractère intrinsèquement dépendant de la machine et doit être évitée.

La dernière phrase est tout ce que vous devez retenir à propos de cette curieuse construction: constantes de Caractère avec plus d'un caractère intrinsèquement dépendant de la machine et doit être évitée.

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