2017-03-23 6 views
2

lassen Sie uns sagen, dass ich ein paar Hardware-Register haben, die innerhalb einer Enum definiert sind:Iterate durch Enums in C?

typedef enum registers 
{ 
REG1 = 0, 
REG2 = 1, 
REG3 = 2, 
REG4 = 4, 
REG5 = 6, 
REG6 = 8, 

REG_MAX, 

}

Ich habe die Standardwerte für diese Register (eigentlich nicht, in welcher Art und Weise beschlossen, sie zu definieren, #define , Anordnung oder ENUM ...):

// This is just conceptual, not really an enum, array or #define :) 
typedef enum values 
{ 
VALUE_REG1 = A, 
VALUE_REG2 = B, 
VALUE_REG3 = C, 
VALUE_REG4 = 53, 
VALUE_REG5 = 88, 
VALUE_REG6 = 24, 

MAX_NUM_REG_VALUES  
} 

I haben eine Funktion, die die Hardware-Register lesen:

uint8 readRegs(uint8 regaddr); 

Nun würde ich gerne die Register enum durchlaufen, und auf jedem Element die readRegs() Funktion aufrufen und mit den enum reg_values ​​vergleichen. Es sieht aus wie:

registers regs; 
    reg_values values; 
    uint8 readfromregs; 

    for (regs = REG1; regs <= REG_MAX; regs++) 
    { 
     readfromregs = readRegs(regs); 
     for (values = VALUE_REG1; reg_values <= MAX_NUM_REG_VALUES; reg_values++) 
     { 
      if (readfromregs != values) 
      { 
       // Value not correct 
      } 

      else 
      { 
       // value correct 
      } 
     } 
    } 

Das wird nicht funktionieren, weil es nicht möglich ist, in Enum auf diese Weise zu wiederholen. Hat jemand eine bessere Lösung? Wie definiert man das Konstrukt enum reg_values ​​? Die Enum-Register müssen behoben werden (dies können keine Änderungen am Array sein).

+3

'MAX_NUM_REG_VALUES' 25 ist, nur damit Sie wissen . – StoryTeller

+2

Sie sollten beginnen '' '' mit ',' in Ihren Enums zu ändern ...;) – LPs

+2

Ein Array, natürlich. Sie könnten ein Array von Paaren oder Strukturen definieren (z. B. pair ). – KonstantinL

Antwort

3

Ich würde wahrscheinlich eine Struktur

struct RegInfo 
{ 
    registers number; 
    values defaultValue; 
} 

Dann ein Array Anpassung der Registernummer auf den Standardwert definieren

struct RegInfo registerInfo[] = 
{ 
    { REG1, VALUE_REG1 }, 
    { REG2, VALUE_REG2 }, 
    { REG3, VALUE_REG3 }, 
    { REG4, VALUE_REG4 }, 
    { REG5, VALUE_REG5 }, 
    { REG6, VALUE_REG6 }, 
}; 

nun die Register iterieren Ich würde erstellen:

for (int i = 0 ; i < sizeof registerInfo/sizeof(RegInfo) ; ++i) 
{ 
    values value = readFromReg(registerInfo[i].number); 
    if (value != registerInfo[i].defaultValue) 
    { 
     // Not the default 
    } 
} 

Wenn Sie eine innere Schleife für jeden Wert wünschen, kann derselbe Trick mit Ausnahme des Arrays direkt vom v sein alues ​​

values allValues[] = { VALUE_REG1, Value_REG2, ... , VALUE_REG6 }; 

Es besteht die Gefahr, dass Sie neue Werte/Register in dem betreffenden Array setzen vergessen werden, aber das ist, was für Unit-Tests sind.

+0

Wenn Sie sich darum sorgen, die Array-Initialisierung während der Wartung zu vermasseln, können Sie' struct RegInfo registerInfo [] = {[0] = {REG1, VALUE_REG1}, [1] = {REG2, VALUE_REG2} , ...} '. Wenn jemand später diese Liste ändern würde, wäre es schwer für sie, etwas zu vermasseln. – Lundin

+0

Ein Optimierungsproblem ist auch, dass Strukturen wie diese eine schlechtere Cache-Performance bieten als ein separates Array von Enums und eines mit Werten. Ich würde sagen, dass die Lesbarkeit des Codes wichtiger ist, aber es ist etwas zu beachten. – Lundin

+0

@Lundin Ich dachte mehr in Bezug auf, ob jemand einen neuen Enum-Wert hinzugefügt und vergessen hat, es dem Array hinzuzufügen. – JeremyP

1

REG_MAX wird 9 und MAX_NUM_REG_VALUES wird 25, so dass Sie diese nicht verwenden können. Sie müssen die Konstanten auf andere Weise aufzählen.

auf der Struktur-Lösung in einer anderen Antwort Basierend von @JeremyP, könnten Sie eine dritte Enum für die tatsächliche Indizes verwenden:

typedef enum 
{ 
    REG_INDEX1 = REG1, 
    REG_INDEX2 = REG2, 
    REG_INDEX3 = REG3, 
    REG_INDEX4 = REG4, 
    REG_INDEX5 = REG5, 
    REG_INDEX6 = REG6, 
    REG_INDEX_N // number of registers 
} reg_index; 

Dies ermöglicht einige Möglichkeiten, die Datenintegrität zu verbessern:

struct RegInfo registerInfo[] = 
{ 
    [REG_INDEX1] = { REG1, VALUE_REG1 }, 
    [REG_INDEX2] = { REG2, VALUE_REG2 }, 
    [REG_INDEX3] = { REG3, VALUE_REG3 }, 
    [REG_INDEX4] = { REG4, VALUE_REG4 }, 
    [REG_INDEX5] = { REG5, VALUE_REG5 }, 
    [REG_INDEX6] = { REG6, VALUE_REG6 }, 
}; 

_Static_assert(sizeof(registerInfo)/sizeof(*registerInfo) == REG_INDEX_N, 
       "Enum not in sync with array initializer"); 

Dies ist die Lösung, die ich empfehlen würde.


Wenn Sie sehr pedantisch mit Datenintegrität und wollen Code eine Wiederholung zu vermeiden, gibt es auch einige böse Makro Magie, die Sie verwenden können.Nämlich „X-Makros“, die stark reduziert die Lesbarkeit auf Kosten kommen:

// whatever A, B and C is supposed to be 
#define A 10 
#define B 11 
#define C 12 

#define REG_LIST \ 
    X(0, A)  \ 
    X(1, B)  \ 
    X(2, C)  \ 
    X(4, 53)  \ 
    X(6, 88)  \ 
    X(8, 24)  \ 

int main (void) 
{ 
    // iterate through the value pairs: 
    #define X(reg, val) printf("reg: %d val:%.2d\n", reg, val); 
    REG_LIST 
    #undef X 
} 

Ebenso können Sie X-Makros verwenden, um die Aufzählungen zu erstellen:

typedef enum // create REG1, REG2, REG4 etc 
{ 
    #define X(key, val) REG##key = key, 
    REG_LIST 
    #undef X 
} registers; 

typedef enum // create VALUE_REG1, VALUE_REG2, VALUE_REG4 etc 
{ 
    #define X(key, val) VALUE_REG##key = val, 
    REG_LIST 
    #undef X 
} values;