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

Je lis un code de l’é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 switch que les types intégraux. Y a-t-il une supercherie macro?

(Vous êtes le seul à pouvoir répondre à la partie “macro” – sauf si vous collez plus de code. Mais il n’y a pas grand-chose pour que les macros fonctionnent – formellement, vous ne pouvez pas redéfinir les mots-clés .

Afin d’obtenir une lisibilité du programme, le développeur plein d’esprit exploite le comportement défini par l’implémentation . 'eax' n’est pas une chaîne, mais une constante multi-caractères . Notez très attentivement les guillemets simples autour de eax . Il est très probable que cela vous donne un int dans votre cas, qui est unique à cette combinaison de caractères. (Assez souvent, chaque caractère occupe 8 bits dans un int 32 bits). Et tout le monde sait que vous pouvez switch un int !

Enfin, une référence standard:

La norme C99 dit:

6.4.4.4p10: “La valeur d’une constante de caractère entier contenant plus d’un caractère (par exemple,” ab “), ou contenant un caractère ou une séquence d’échappement qui ne correspond pas à un caractère d’exécution d’un octet, est définie par l’implémentation. ”

Selon la norme C (6.8.4.2 Déclaration de commutation)

3 L’expression de chaque étiquette de cas doit être une expression constante d’entier

et (6.6 expressions constantes)

6 Une expression de constante entière doit avoir un type entier et avoir uniquement des opérandes qui sont des constantes entières, des constantes d’énumération, des constantes de caractères , des expressions sizeof dont les résultats sont des constantes entières et des constantes flottantes qui sont les opérandes immédiats des casts. Les opérateurs de dissortingbution dans une expression de constante entière doivent uniquement convertir les types arithmétiques en types entiers, sauf en tant qu’opérande à l’opérateur sizeof.

Maintenant, qu’est-ce que 'eax' ?

La norme C (6.4.4.4 Constantes de caractères)

2 Une constante de caractère entier est une séquence d’un ou plusieurs caractères multi-octets entre guillemets simples , comme dans ‘x’ …

Donc 'eax' est une constante de caractère entier selon le paragraphe 10 de la même section

  1. … La valeur d’une constante de caractère entier contenant plus d’un caractère (par exemple, “ab”), ou contenant un caractère ou une séquence d’échappement qui ne correspond pas à un caractère d’exécution à un octet, est définie par l’implémentation.

Donc, selon la première citation mentionnée, il peut s’agir d’un opérande d’une expression constante entière qui peut être utilisée comme une étiquette de casse.

Faites attention à ce qu’une constante de caractère (entre guillemets simples) ait le type int et ne soit pas identique à un littéral de chaîne (une séquence de caractères entre guillemets) qui a un type de tableau de caractères.

Comme d’autres l’ont déjà dit, il s’agit d’une constante int et sa valeur réelle est définie par l’implémentation.

Je suppose que le rest 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, donc tout se passe bien, non? … faux.

Dans un commentaire @Davislor énumère quelques valeurs possibles pour ‘eax’:

0x65 , 0x656178 , 0x65617800 , 0x786165 , 0x6165 ou autre chose

Notez la première valeur potentielle? C’est juste 'e' , en ignorant les deux autres caractères. Le problème est que le programme utilise probablement 'eax' , 'ebx' , etc. 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 beau, n’est-ce pas?

La bonne partie à propos de “implementation-defined” est que le programmeur peut vérifier la documentation de son compilateur et voir s’il fait quelque chose de sensé avec ces constantes. Si c’est le cas, gratuitement chez vous.

La mauvaise partie est que d’autres pauvres peuvent prendre le code et essayer de le comstackr en utilisant un autre compilateur. Erreur de compilation instantanée. Le programme n’est pas portable.

Comme @zwol l’a souligné dans les commentaires, la situation n’est pas aussi grave que je le pensais, dans le mauvais cas, le code ne comstack pas. Cela vous donnera au moins un nom de fichier et un numéro de ligne exact pour le problème. Cependant, vous n’aurez pas de programme de travail.

Le fragment de code utilise une singularité historique appelée constante de caractère multi-caractères , également appelée multi-caractères .

'eax' est une constante entière dont la valeur est définie par l’implémentation.

Voici une page intéressante sur les multi-caractères et comment ils peuvent être utilisés mais ne devraient pas:

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


En regardant plus loin dans le rétroviseur, voici comment le manuel original de Dennis Ritchie du bon vieux temps ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) spécifiait les constantes de caractères. .

2.3.2 Constantes de caractères

Une constante de caractère est 1 ou 2 caractères entre guillemets simples ” ' ‘ ‘. Dans une constante de caractère, une seule citation doit être précédée d’une barre oblique inverse ” \ ”. Certains caractères non graphiques, et ” \ ” lui-même, peuvent être échappés selon le tableau suivant:

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

L’échappement ” \ddd ” se compose de la barre oblique inverse suivie de 1, 2 ou 3 chiffres octaux qui sont utilisés pour spécifier la valeur du caractère souhaité. Un cas particulier de cette construction est ” \0 ” (non suivi par un chiffre) qui indique un caractère nul.

Les constantes de caractères se comportent exactement comme des entiers (pas, en particulier, comme des objects de type caractère). Conformément à la structure d’adressage du PDP-11, une constante de caractère de longueur 1 a le code pour le caractère donné dans l’octet de poids faible et 0 dans l’octet de poids fort; une constante de caractère de longueur 2 a le code du premier caractère de l’octet inférieur et celui du deuxième caractère de l’octet de poids fort. Les constantes de caractère comportant plus d’un caractère dépendent insortingnsèquement de la machine et doivent être évitées.

La dernière phrase est tout ce dont vous devez vous souvenir au sujet de cette construction curieuse: Les constantes de caractères comportant plus d’un caractère dépendent de manière inhérente de la machine et doivent être évitées.