2015-08-03 5 views
2

J'utilise des valeurs de recenseur pour les drapeaux:opération Bitwise avec (signé) valeur ENUM

typedef enum 
{ 
    a = 0x00, 
    b = 0x01u, // the u has no influence, as expected 
    c = 0x02u, // the u has no influence, as expected 
... 
} enum_name; 

volatile unsigned char* reg = SomeAddress; 
*reg |= b; 

Selon MISRA-C: 2004 opérations binaires ne doivent pas se faire avec un type signé. Malheureusement, mon compilateur IAR utilise signé int (ou short ou char) comme type sous-jacent d'enums, et la seule option que je peux trouver concerne la taille, pas la signature ("--enum-is-int").

+0

Bien sûr, je peux le lancer, je suis à la recherche d'une approche globale. – lkanab

+1

Qu'entendez-vous par «approche globale»? Comme la plupart des règles MISRA, ils vous disent d'éviter un code parfaitement bon. C'est parfaitement bon code. Vous devrez empirer le code avec un casting redondant afin de se conformer. –

+1

Une option privilégiée serait 'volatile unsigned char * reg = (volatile unsigned char *) SomeAddress; ' –

Répondre

2

selon le IAR C/C++ Development Guide for ARM, pages 169 et 211, vous pouvez définir le type de vos enum s si vous activez les extensions de langage IAR (-e l'option de ligne de commande, ou projet>options>C/C++>Langue>Autoriser les extensions IAR dans l'IDE).

En particulier, vous devez définir une valeur "sentinel" supplémentaire, pour vous assurer que le compilateur choisit le bon type. Il préfère les types signés, et utilise le plus petit type entier possible, donc la sentinelle doit être le plus grand entier positif que le type entier non signé correspondant peut décrire. Par exemple,

typedef enum { 
    /* ... */ 
    enum_u8_sentinel = 255U 
} enum_u8; 

typedef enum { 
    /* ... */ 
    enum_u16_sentinel = 65535U 
} enum_u16; 

typedef enum { 
    /* ... */ 
    enum_u32_sentinel = 4294967295UL 
} enum_u32; 
+0

Bien que cela soit vrai, il s'agit d'une extension de langage spécifique à l'implémentation qui n'est pas portable et qui, en soi, viole la règle MISRA-C: 2004 1.1 sans déviation. Cela équivaut à MISRA C: 2012 Règle 1.2 – Andrew

+0

Je n'ai pas accès aux spécifications de MISRA, donc je vais vous croire sur parole. La solution portable, bien sûr, consiste à utiliser des macros préprocesseur à la place. –

2

Peu importe si le type sous-jacent est signé de unsigned, à condition que vous n'utilisiez que des valeurs positives pour votre énumération, car une valeur positive devrait avoir la même représentation qu'un type signé ou non signé. Standard dit en 6.2.6.2 Représentation des types/types entiers §5: Une représentation d'objet valide (non-piège) d'un type entier signé où le bit de signe est zéro est une représentation d'objet valide du type non signé correspondant , et doit représenter la même valeur.

Ainsi, vous pouvez sans risque faire la distribution non signée si vous le souhaitez. Quoi qu'il en soit, si le type sous-jacent est char (ou a été unsigned char), il peut être promu (en silence) en int avant tout calcul.

à mon humble avis, MISRA-C: 2004 indique que les opérations bitwize ne doivent pas se faire avec un type signé, parce que la norme indique explicitement que la représentation d'un nombre négatif est défini par l'implémentation:

Pour les types entiers signés, les bits de la représentation de l'objet doivent être divisés en trois groupes : les bits de valeur, les bits de remplissage et le bit de signe. Il n'y a pas besoin de bits de remplissage; il doit y avoir exactement un bit de signe ... Si le bit de signe est une, la valeur doit être modifiée dans l'une des façons suivantes:

  • la valeur correspondante avec le bit de signe 0 est niée (signe et ordre de grandeur);
  • le bit de signe a la valeur - (2N) (complément à deux);
  • le bit de signe a la valeur - (2N - 1) (complément des uns).

  • Lequel de ces applique est mise en œuvre définis (mettent l'accent sur le mien)

TL/DR: Si vous avez pas d'avertissement (et vous ne devriez pas pour Bitwise ou |) vous peut en toute sécurité utiliser aucun casting du tout. Si vous affectez au type non signé une valeur positive, la représentation reste inchangée et vous pouvez également effectuer le cast si vous (ou vos règles d'entreprise) décidez de suivre MISRA-C, ainsi vous pouvez également lancer en toute sécurité vers un type non signé

+0

La signesse est importante lorsque vous utilisez la complémentaire: * ret &= ~b; (C'est en tout cas ce que pense le CSTAT de l'IRA). – lkanab

+0

@lkanab Pour une machine non-two's-complement, il est concevable que cela se comporte mal: '~ b' a le motif de bits correctement inversé, mais dans un type signé. Si '* ret 'a un type non signé, la conversion signée à non signée modifie le modèle de bits. – Potatoswatter

+0

Autant que je sache, les enquêteurs ont le type 'int' indépendamment du type sous-jacent. Vous pouvez forcer le type sous-jacent à 'unsigned' en ajoutant un énumérateur comme' force_unsigned = -1u'. Mais, les autres énumérateurs semblent toujours être 'int', et nommer' force_unsigned' dans une expression provoquera un débordement d'entier instantané. (L'astuce fonctionne en C++, cependant.) – Potatoswatter