2017-10-17 8 views
0

Cadre:Accès partiel à C de par octet ENUM

  1. Je définir une ENUM en C99:

    enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX}; 
    
  2. Je veillerai avec le temps affirme que la compilation TEST_ENUM_ITEM_MAX ne dépasse pas UINT16_MAX. Je suppose que peu endian comme ordre de byte.

  3. I ont une fonction serialize-en-tampon avec les paramètres suivants:

    PutIntoBuffer(uint8_t* src, uint32_t count); 
    
  4. I sérialiser une variable contenant une valeur dans une mémoire tampon. Pour cette tâche, je avoir accès à la variable, tenant le ENUM, comme ceci:

    enum MY_ENUM testVar = TEST_ENUM_ITEM; 
    
    PutIntoBuffer((uint8_t*) &testVar, sizeof(uint16_t)); 
    

Question: Est-il légitime d'accéder au ENUM (qui est un int) de cette façon? La norme C garantit-elle le comportement souhaité?

+0

Si l'enum peut être plus grand que U8_MAX, il sera probablement étrange de le lancer sur le pointeur U8. – Fredrik

Répondre

1

Il est légitime que "cela fonctionnera si int est 16 bits". Il ne viole pas non plus les règles d'alias de pointeur, à condition d'utiliser un type de caractère tel que uint8_t. (La désérialisation est une autre histoire cependant.)

Cependant, le code n'est pas portable. Dans le cas int est de 32 bits, les constantes d'énumération tourneront aussi 32 bits, tout comme la variable enum lui-même. Ensuite, le code deviendra dépendant de l'endianess et vous pourriez finir par lire les ordures. La vérification de TEST_ENUM_ITEM_MAX par rapport à UINT16_MAX ne résout pas cela.

La bonne façon de sérialiser un ENUM est d'utiliser une lecture seule table de consultation prégénérée qui est garanti 8 bits, comme ceci:

#include <stdint.h> 

enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX}; 

static const uint8_t MY_ENUM8 [] = 
{ 
    [TEST_ENUM_ITEM1] = TEST_ENUM_ITEM1, 
    [TEST_ENUM_ITEM2] = TEST_ENUM_ITEM2, 
}; 

int main (void) 
{ 
    _Static_assert(sizeof(MY_ENUM8)==TEST_ENUM_ITEM_MAX, "Something went wrong"); 
} 

La syntaxe de initialisateur désigné améliore l'intégrité des données, devrait être mis à jour enum lors de la maintenance. De même, l'assertion statique fera en sorte que la liste contienne le bon nombre d'éléments.

+0

Dans quel cas est-ce que je lis des ordures pour int 32 bits et peu endianess? Les valeurs jusqu'à UINT16_MAX sont-elles sûres à lire? – user259819

+0

@ user259819 Ah, les ordures (sous la forme de tous les zéros) ne se produiront qu'avec le gros boutiste. Mais de toute façon, il n'y a aucune raison d'utiliser des trucs bizarres, non portables, quand vous pouvez obtenir du code portable déterministe qui est généré au moment de la compilation. – Lundin