8
votes

Comment spécifier une taille ENUM dans GCC?

Je veux spécifier une taille d'énumération de 64 bits pour une énumération. Comment est-ce possible via GCC? Le code n'a pas besoin d'être «portable» en ce que je ne suis intéressé que de faire fonctionner le code sur la compilation de GCC pour X86-32 et X86-64 Linux. Cela signifie que tout piratage pouvant fournir la fonctionnalité que je veux va bien tant que cela fonctionne pour ces cibles.

donné à ce code: p> xxx pré>

Ceci imprime actuellement 4, Alors que je veux pouvoir forcer la taille à être 8. Tentative de spécifier des valeurs dans l'affectation enum plus de 4 octets entraînant un avertissement. Par exemple, p> xxx pré>

produirait: p> xxx pré>

un Réponse à une question similaire ici ne semble pas donner de bons résultats. C'est-à-dire que le même avertissement est produit à la suite de: p> xxx pré>

Remarque: l'avertissement de plusieurs caractères peut être éteint en compilant avec -wno-multichar .


Since Les gens sont intéressés pourquoi je fais cela, j'ai écrit un moteur de désassembleur. Je reçois chaque partie d'une instruction comme une chaîne. Je veux donc que l'énumération ressemble à ceci: p> xxx pré>

Je peux ensuite stocker facilement des informations sémantiques avec un code comme celui-ci: P>

if(strcmp(example_insn, "mov") == 0) {
    insn = mov;
} else if(strcmp(example_insn, "cmp") == 0) {
    insn = cmp;
} ...


10 commentaires

Pourquoi voudriez-vous faire cela? On dirait que vous n'utilisez pas Enum d'une manière "propre".


Qu'est-ce que sur la terre '12345' représenterait? Un seul caractère contenant 5 caractères? Si vous souhaitez stocker une valeur numérique, écrivez-le sans ' - Je ne reçois pas d'avertissements avec GCC sur x64.


JFTR, 'ABC' est une extension MSVC non standard pour 'A' << (U * Char_bit) | 'B' << (V * CHAR_BIT) | 'C' << (W * Char_bit) ... Avec la cartographie définie par la mise en œuvre entre U, V, W, ... et l'ensemble de nombres réels.


@DANFEGO: J'ai ajouté une justification.


@Matteoitalia: Je veux stocker la représentation numérique d'une chaîne comme uint64_t. Regardez la justification.


@Mikekwan: Ensuite, votre problème n'est pas avec Enum S, mais avec chaîne uint64_t littéraux.


'12345' est en fait une caractéristique standard de la langue. La valeur est définie par la mise en œuvre (ce qui signifie qu'il est à peu près inutile pour le code portable).


@KeithThompson: Désolé, je ne connaissais pas les littéraux multi-micracter, c'est la première fois que je chante sur eux.


Mais toutes les constantes de caractères sont de type int , et je ne pense pas que GCC a une extension pouvant remplacer cela.


Édité pour corriger null (qui est un null pointeur constant) à "caractères nuls".


9 Réponses :


7
votes

Vous pouvez utiliser un Union type: xxx


0 commentaires

0
votes

perhas que vous pouvez utiliser définit des définitions?

enum
{
 garbage1,
 garbage2,
 sentinel = 12345L
}


1 commentaires

#define est mon dernier recours. Je préférerais une énumération. Votre suggestion d'énumération n'est pas tout à fait ce que je veux. J'en ai besoin pour représenter une chaîne.



6
votes

Bien que la norme C99 spécifie qu'un énorme ne puisse être basé sur quoi que ce soit un int (§6.7.2.2 ¶2) 1 , il semble que gcc suit l'idée C ++ que, si une valeur dans un Enum est plus grosse qu'un int , il peut la baser sur un plus grand type entier. Je n'ai aucun problème avec ce code, ni sur x86 ni sur x64: xxx

sur x86 i get xxx

et sur x64 (sur ma machine), je reçois xxx

bien que , demandant un respect pédant de la norme, je reçois, comme prévu: xxx


  1. En fait, c'est un peu plus compliqué; ¶4 Spécifie que la mise en œuvre est libre de choisir comme "Type de base" tout type particulier "compatible avec char , type d'entiers signé ou un type d'entier non signé", tant qu'il peut représenter Tous les éléments du Enum .

    D'autre part, ¶2 Spécifie que chaque membre du Enum doit être représentable comme int , même si la mise en œuvre est libre de baser votre < Code> Enum Même sur un bit Gazillion Bit Entier, les constantes définies pour cela ne peuvent pas être quelque chose qui ne peut être représenté par un int . Ainsi, cela signifie que dans la pratique le compilateur ne basant pas le enum sur quelque chose de plus grand qu'un int , mais il peut < / em> base sur quelque chose de plus petit si vos valeurs ne nécessitent pas la gamme complète de int .

    grâce à @ jons34yp pour indiquer mon erreur initiale.


7 commentaires

Malgré cet avertissement, cette solution est-elle garantie de fonctionner comme prévu avec mes plates-formes cible? En outre, est-il possible d'adapter cela au style littéral à la chaîne / à plusieurs caractères que je veux? Je suppose que je pourrais toujours générer ces chiffres, mais c'est moins lisible.


@Mikekwan: Cet avertissement apparaît uniquement si vous demandez explicitement la conformité standard de Pedantic ( -ansi -peantique ), en ce qui concerne gcc ne contient aucun problème à fonder le Enum S sur les types plus gros que int si nécessaire (comme vous pouvez le voir, je l'ai testé sur X86 et X64 et ça marche bien). En ce qui concerne les littéraux multi-charmes, j'essaie de regarder s'il y a un moyen de les faire travailler.


Si vous souhaitez spécifiquement des énumes 64 bits, vous pouvez le faire: Enum quelque_eum {/ * ... * / max = 0x7FFFFFFFFFFFFFFFF}; . Avoir un membre de cette valeur garantit que le type nécessite (au moins) 64 bits (ou que le compilateur le rejetera).


@KeithThompson: 0x7FFFFFFFFFFFFFFLL , je pense. En ce qui concerne le problème des littéraux multicharacter, je pense qu'il n'y a pas de solution.


@Matteoitalia: le suffixe ll n'est pas nécessaire; Une constante hexagonale est d'un type assez grand pour tenir sa valeur. Et je pense que vous avez raison de ne pas avoir de solution pour les littéraux multi-micracters - autres que ne les utilisant pas (voir ma réponse).


@Matteoitalia. Votre réponse est fausse. §6.7.2.2 ¶2 Ne parle que sur les constantes de dénombrement (le bit A = 12345 ), § 6.7.2.2 ¶4 dit "Chaque type énuméré <...>. Le choix de Type est défini par la mise en œuvre, "


@ JONS34YP: Vous avez raison, je corrigerai la réponse; Néanmoins, étant donné que chaque valeur du Enum ne peut pas être supérieure à un int (en raison de ¶2), il ne serait pas logique de le rendre plus grand que INT .



5
votes

Vous avez mal interprété l'avertissement, ce qu'il dit que les littéraux de caractères sont toujours de type int , jamais de type long ou long long Assurez-vous d'utiliser les numéros de décalage correct.


2 commentaires

C'est une belle solution. Je vais essayer plus tard. Savez-vous si cela peut être converti en macro en quelque sorte?


Cette solution fonctionne parfaitement. Je vais accepter cette réponse et faire une nouvelle écriture démontrant comment l'utiliser.



8
votes

Comme la réponse de Matteo Italia dit, GCC vous permet de définir un type d'énumération de 64 bits en spécifiant une valeur de 64 bits pour l'un des membres. Par exemple: xxx pré>

comme pour votre utilisation de 'mov' code>, 'CMP' code>, etc., il n'y a pas de corrélation nécessaire entre la représentation d'un littéral de chaîne comme "mov" code> et la représentation d'une constante de caractère multi-caractères similaire à 'mov' code>. p>

Ce dernier est Legal (et soutenu par GCC), mais la valeur est définie par la mise en œuvre. La norme indique que le type est toujours int code> et GCC ne semble pas avoir une extension qui vous permet de remplacer cela. Donc, si int code> est 4 octets, puis 'sysenter' code>, s'il est accepté du tout, il n'a pas nécessairement la valeur que vous recherchez. GCC semble ignorer tous mais les octets à faible commande d'une telle constante. La valeur de la constante semble être cohérente à travers les systèmes Big-Endian et Little-Endian - ce qui signifie qu'il ne sera pas em> correspond toujours à la représentation d'un littéral de chaîne similaire. P>

Par exemple, ce programme: P>

'abcd'     = 0x61626364
'abcdefgh' = 0x65666768
*(unsigned*)s1 = 0x61626364
*(unsigned*)s2 = 0x61626364


2 commentaires

En ce qui concerne que cela puisse être fait avec une hache plus rapide, je ne crois vraiment pas. J'utilise la haquetable du noyau Linux en ce moment. Cela prend une clé et une taille d'une clé. Cela signifie donc que je devrais réellement faire le rembourrage que je fais actuellement de toute façon. La raison en est que je suis en fait simplifié la justification - les cordes générées de libopcodes que j'utilise pour démonter avoir des caractères spatiaux de rembourrage qui doit être dépouillé. L'utilisation d'une hache utiliserait exactement la même quantité de calcul mais ajoutez également le coût du calcul du hachage et d'ajouter à la haquetable.


Après une enquête, je conviens que le problème réel est qu'un littéral multicapare ne peut être que 4 octets (au moins moins de X86-32 et X86-64). Je ne trouve pas de citation pour cela, cependant. La solution par Johansson fonctionne bien à la place.



0
votes

Votre meilleur pari est probablement à l'aide du système de construction pour générer automatiquement un ensemble de définition. De cette façon, vous obtiendrez également ladimité droite.

Un exemple de programme GEN-INSTRUCTION CODE> pourrait ressembler à ce p>

instructions.h : instructions.list gen-instructions
    ./gen-instructions `cat $<` > $@


0 commentaires

1
votes

par johansson frappe le clou sur la tête avec sa réponse ICI . Comme exemple concret de la manière d'utiliser cette technique, j'ai écrit ce programme ( insn_enum.c code>): xxx pré>

Ceci peut être compilé avec le suivant Makefile code>: p> xxx pré>

exécuté avec ./ insn_enum_32 && ./insn_enum_64 code> imprimera: p>

gcc -std=gnu99 -m32 -pedantic -Wall insn_enum.c -o insn_enum_32
insn_enum.c:13:13: warning: ISO C restricts enumerator values to range of ‘int’
gcc -std=gnu99 -m64 -pedantic -Wall insn_enum.c -o insn_enum_64
insn_enum.c:13:13: warning: ISO C restricts enumerator values to range of ‘int’


0 commentaires

1
votes

Juste pour répondre à la question initiale dans le titre - C ++ 11 vous permet de spécifier le type d'énorme, et donc sa taille:

enum class mynamedenum : long {
  FOO,
  BAR
}


0 commentaires

1
votes

Il n'y a pas de moyen officiel de spécifier Enum Strong> Taille. Peut-être pas 100% appliqué à votre cas, mais avec ce piratage, vous pourriez obtenir une taille d'énumération ciblée pour être multiplate-forme. Vous devez utiliser le mot-clé __ attribut __ code> avec le paramètre Emballé code> pour réduire la taille enum jusqu'à la valeur maximale de la liste Enum.

Jetez un coup d'œil sur l'exemple ci-dessous: P>

Sizeof en_8b_t: 8
Sizeof en_4b_t: 4
Sizeof en_2b_t: 2
Sizeof en_1b_t: 1
Default enum size is: 4


2 commentaires

C'est une bonne suggestion bien que cela ne fonctionne que pour le compilateur GCC.


Oui, la question a été posée pour GCC. Les attributs sont spécifiques pour différents compilateurs.