Forum: PC-Programmierung Name von enum variable zusammensetzen


von Johannes (Gast)


Lesenswert?

Hallo,
ich habe eine funktion in c, der ich eine variable übergeben muss.
Die Variable bekomme ich von einer anderen Funktion (z.B.int32 48000)
Die Frequenz muss ich nun einer set_audioformat übergeben.
Diese möchte aber werte von Enums haben
1
void set_audioformat(enum audio_frequency frequency,
2
                     enum audio_channels channels,
3
                     enum audio_samplesize samplesize,
4
                     enum audio_ampletype sampletype);

ein enum sieht z.B. wie folgt aus
1
enum audio_frequency {
2
    frequency_unknown = 0,
3
    frequency_8000 = 1,
4
    frequency_11025 = 2,
5
    frequency_12000 = 3,
6
    frequency_16000 = 4,
7
    frequency_22050 = 5,
8
    frequency_24000 = 6,
9
    frequency_32000 = 7,
10
    frequency_44100 = 8,
11
    frequency_48000 = 9,
12
    frequency_96000 = 10,
13
    frequency_192000 = 11
14
};

Der wert der Frequenz von audio_frequenzy wird dann in einem 4-Bit-Feld 
in einem Header eingetragen.Wenn ich jetzt für die Frequenz einfach den 
Wert 48000 übergebe, wird das natürlich nicht hinhauen. Wie bekomme ich 
am besten den namen vom enum audio_frequenzy heraus um diesen zu 
übergeben?

von Theor (Gast)


Lesenswert?

Mit einer Kette von if-else-Anweisungen oder einer 
switch-case-Anweisung.

von Theor (Gast)


Lesenswert?

Der von Dir angedeutete Weg funktioniert nicht.

Du kannst nicht zur Laufzeit den Namen eines enum-Wertes zusammensetzen.

von Johannes (Gast)


Lesenswert?

Theor schrieb:
> Mit einer Kette von if-else-Anweisungen oder einer
> switch-case-Anweisung.

Mhh, deswegen habe ich gefragt, in der Hoffnung das es jemand eine 
schönere lösung gibt. Das wird jetzt viel umstrickerei.

Theor schrieb:
> Du kannst nicht zur Laufzeit den Namen eines enum-Wertes zusammensetzen.

Das habe ich mir fast gedacht.


Aber ich danke euch trotzdem

von Theor (Gast)


Lesenswert?

Johannes schrieb:
> Theor schrieb:
>> Mit einer Kette von if-else-Anweisungen oder einer
>> switch-case-Anweisung.
>
> Mhh, deswegen habe ich gefragt, in der Hoffnung das es jemand eine
> schönere lösung gibt. Das wird jetzt viel umstrickerei.

Wieso?
Das ist ne Sache von drei Minuten. Einschliesslich Kaffee holen.
1
 ...
2
else if (f == 11025) return frequency_11025;
3
 ...
4
else return frequency_unknown;

von Johannes (Gast)


Lesenswert?

Theor schrieb:
> Das ist ne Sache von drei Minuten

Das ist auch nicht das Problem. Das Problem ist einfach nur, dass jetzt 
größere Blöcke reinkommen, wo ich mir den Wert hole.

Habe ich auch schon gleich alles drinn

von Theor (Gast)


Lesenswert?

Johannes schrieb:
> Theor schrieb:
>> Das ist ne Sache von drei Minuten
>
> Das ist auch nicht das Problem. Das Problem ist einfach nur, dass jetzt
> größere Blöcke reinkommen, wo ich mir den Wert hole.


Höchsten einen "Block". Du schreibst einfach eine Funktion.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

1
...
2
3
switch (frequency_in) {
4
  case 8000:
5
    frequency = frequency_8000;
6
    break;
7
  case 11025:
8
    frequency = frequency_11025;
9
    break;
10
usw. ...
11
  default:
12
    frequency = frequency_unknown;
13
    break;
14
}

von Georg A. (georga)


Lesenswert?

In moderneren Sprachen könnte man ein assoziatives Array/Hash machen, 
der Key wäre der Integerwert, der Value dann der Enum.

In plain C gehts aber auch mit etwas Handarbeit. Ein Array bestehend aus 
einem Elementtyp mit Integer und dazuhörigem Enum und dann eine 
for-schleife, die den Int sucht und das Enum zurückgibt. Ist etwas 
schöner als die if/switch-Spaghettis.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was natürlich geht, ist das hier:
1
enum audio_frequency {
2
    frequency_unknown = 0,
3
    frequency_8000 = 8000,
4
    frequency_11025 = 11025,
5
    frequency_12000 = 12000,
6
    frequency_16000 = 16000,
7
    frequency_22050 = 22050,
8
    frequency_24000 = 24000,
9
    frequency_32000 = 32000,
10
    frequency_44100 = 44100,
11
    frequency_48000 = 48000,
12
    frequency_96000 = 96000,
13
    frequency_192000 = 192000
14
};

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Georg A. schrieb:
> Ein Array bestehend aus
> einem Elementtyp mit Integer und dazuhörigem Enum und dann eine
> for-schleife, die den Int sucht und das Enum zurückgibt. Ist etwas
> schöner als die if/switch-Spaghettis.

Das ist keineswegs schöner, da der Rechenaufwand für solch eine Schleife 
mit O(n) mit n: Anzahl der Tabelleneinträge skaliert. Der Compiler hat 
hingegen keine Möglichkeit, die Schleife so zu optimieren, dass sie 
weniger stark skaliert.

Aus einer switch/case-Konstruktion erzeugen moderne Compiler jedoch 
häufig einen binären Suchbaum, der mit O(log(n)) skaliert. Außerdem ist 
der gesamte Vorgang bereits zur Kompilierzeit vollständig bestimmt, 
wohingegen die Schleife dynamische Elemente besitzt.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Theor schrieb:
> Der von Dir angedeutete Weg funktioniert nicht.
>
> Du kannst nicht zur Laufzeit den Namen eines enum-Wertes zusammensetzen.

Ja. Der Name existiert nur im Compiler. Zur Laufzeit, zu der man den 
Wert hat, gibt's den Namen gar nicht mehr.

Georg A. schrieb:
> In plain C gehts aber auch mit etwas Handarbeit. Ein Array bestehend aus
> einem Elementtyp mit Integer und dazuhörigem Enum und dann eine
> for-schleife, die den Int sucht und das Enum zurückgibt. Ist etwas
> schöner als die if/switch-Spaghettis.

Was soll daran schöner sein als an einem simplen:
1
enum audio_frequency frequency_to_enum(int32_t frequency)
2
{
3
    switch (frequency)
4
    {
5
        default:     return frequency_unknown;
6
        case   8000: return frequency_8000;
7
        case  11025: return frequency_11025;
8
        case  12000: return frequency_12000;
9
        case  16000: return frequency_16000;
10
        case  22050: return frequency_22050;
11
        case  24000: return frequency_24000;
12
        case  32000: return frequency_32000;
13
        case  44100: return frequency_44100;
14
        case  48000: return frequency_48000;
15
        case  96000: return frequency_96000;
16
        case 192000: return frequency_192000;
17
    }
18
}
Da seh ich jetzt nicht mehr "Spaghetti" drin, als in einem Array und 
einer zusätzlichen Suchfunktion dafür.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Was soll daran schöner sein als an einem simplen:

Das könnte man sich schenken, wenn die enum-Werte den tatsächlichen 
entsprechen, wie ich weiter oben vorgeschlagen habe.

Man muss nur den Sonderfall erfassen, daß eine unbekannte Frequenz 
vorliegt.

Die Frage ist, ob das eine Operation ist, die zur Laufzeit des 
Programmes häufiger auftritt, oder ob sowieso nur mit bekannten, d.h. 
wohldefinierten Frequenzen gearbeitet wird.

Dann wäre der einzige Grund, andere enum-Konstanten zu verwenden, der 
reduzierte Werteumfang und damit Speicherplatzbedarf.

Ich habe aber nicht den Eindruck, daß diese Audioanwendung hier auf 
einem 8-Bit- oder 16-Bit-µC laufen soll.

von Theor (Gast)


Lesenswert?

Theor schrieb:
> Der von Dir angedeutete Weg funktioniert nicht.
>
> Du kannst nicht zur Laufzeit den Namen eines enum-Wertes zusammensetzen.

Da muss ich mich dann doch, wenigstens teilweise korrigieren.

Man kann zur Kompilierungszeit mit Präprozessor-Kommandos erreichen, 
dass die Identifizierer von Aufzahlungskonstanten konstruiert , und 
auch passende Funktionen erzeugt werden, welche die Identifizierer einem 
numerischen Wert oder umgekehrt zuordnen können.

Ich habe das zwar für möglich gehalten, hielt es aber für recht 
aufwendig, dem TO das im Einzelnen zu erklären.

Dieser Thread Beitrag "Re: Enum Export für Docu" hat 
aber meine Aufmerksamkeit erregt und siehe da, in Dr. Sommers Antwort 
steckt eine Link zu stackoverflow 
https://stackoverflow.com/questions/28828957 zu dem Thema in dem eine 
Zusammenstellung von Methoden mit Präprozessorkommandos enthalten ist.

Insbesondere 
https://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in-c 
scheint mir relativ gut zu der Frage hier zu passen, wenn man den Code 
auch noch verändern muss um genau das Ziel der Frage zu erreichen.

Ob das dem TO nun direkt hilft, weiß ich nicht. Es ist doch recht 
komplex und ich scheue mich selbst auch eher davor, solche 
Konstruktionen zu verwenden.

Aber es geht und deswegen füge ich das hier dem Thread hinzu.

von Georg A. (georga)


Lesenswert?

Andreas S. schrieb:
> Das ist keineswegs schöner, da der Rechenaufwand für solch eine Schleife
> mit O(n) mit n: Anzahl der Tabelleneinträge skaliert. Der Compiler hat
> hingegen keine Möglichkeit, die Schleife so zu optimieren, dass sie
> weniger stark skaliert.

Mei, immer diese Theoretiker ;) Für den konkreten Fall wird das mit 
einer überschaubaren Zahl von Einträgen vermutlich einmal alle heiligen 
Zeiten ausgeführt.

Die Schreibweise in Tabellenform ohne viel Extraschlüsselwörter finde 
ich jedenfalls schöner und vor allem recht universell anwendbar.
1
hash_type tab[]={
2
 {8000, frequency_8000},
3
 ...
4
 {192000, frequency_192000},
5
 {-1,-1} // oder was auch immer
6
};

von Rolf M. (rmagnus)


Lesenswert?

Rufus Τ. F. schrieb:
> Rolf M. schrieb:
>> Was soll daran schöner sein als an einem simplen:
>
> Das könnte man sich schenken, wenn die enum-Werte den tatsächlichen
> entsprechen, wie ich weiter oben vorgeschlagen habe.

Klar. Ich hatte das so verstanden, dass der enum vorgegeben ist und 
nicht umdefiniert werden kann.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johannes schrieb:
> Die Variable bekomme ich von einer anderen Funktion (z.B.int32 48000)

Warum arbeitet diese Funktion mit konkreten Zahlenwerten statt mit den 
vorgegebenen enums?

Du solltest besser die Ursache für das Problem beheben und nicht ein 
Pflaster draufkleben mit einer Mapping-Funktion.

: Bearbeitet durch Moderator
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.