Forum: Mikrocontroller und Digitale Elektronik ARM-GCC: 64 Bit breites enum


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

für einen etwas merkwürdigen Anwendungfall benötige ich ein Logik-Array 
mit mindestens 59 Bit. Aufgrund der vereinfachten logischen Operationen 
wären benannte 64 Bit breite Bitmasken hier sehr praktisch.

Stellt sich die Frage: Können Enums 64 Bit breit sein? Der C-Standard 
sagt zu enum nur "muss mindestens Int abbilden können".

Also flugs ausprobiert:
1
enum {
2
    e_test1 = 0x8000000080000000,
3
};
4
5
    uint64_t test = e_test1;
6
    printf("\n Enum: %llx\n", test);
7
    switch( test )
8
    {
9
        case 0x8000000080000000:
10
            printf("Glück gehabt\n");
11
            break;
12
        default:
13
            printf("Pech gehabt\n");
14
    }
Der Kompiler zeigt keine neuen Fehler, Warnungen oder Badboxes und das 
LCD zeigt den korrekten Wert an mit dem Hinweis, ich habe Glück gehabt.

Damit kommen Folgefragen:
 a) Wieso unterstützt der ARM-GCC 64 Bit breite Enums?

 b) Werden dadurch plötzlich alle Enums im Binary 64 Bit breit?

 c) Kann ich mir mit den breiten Enums irgendwie in den Fuß schießen?

: Bearbeitet durch User
von Daniel -. (root)


Bewertung
0 lesenswert
nicht lesenswert
enum class X : uint64_t { ...  };

ist das eine Option?

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
2 lesenswert
nicht lesenswert
Walter T. schrieb:
> a) Wieso unterstützt der ARM-GCC 64 Bit breite Enums?

Warum sollte er nicht? Sofern er int64_t kennt, d.h. 64-Bit-Werte 
überhaupt verarbeiten kann, würde ich das erwarten.

enums sind nur hübsche Konstanten, mehr nicht. Da steckt kein 
Spezialcode dahinter.

> b) Werden dadurch plötzlich alle Enums im Binary 64 Bit breit?

Finde es selbst heraus, der sizeof -Operator dürfte Dir da helfen.

von Peter D. (peda)


Bewertung
3 lesenswert
nicht lesenswert
Walter T. schrieb:
> mit mindestens 59 Bit.

Klingt nach DCF-77. Die Wahnsinnsdatenrate von riesigen 1 Baud kann man 
bequem in knallharter Echtzeit zu den Zeitvariablen addieren. Sie 
erstmal zu speichern ist unnötig.

Enums nimmt man typisch für Aufzählungen und nicht für Bitmasken. Der 
Sinn eines 64Bit-Enums erschließt sich mir daher nicht.

von Tarzan Betrachter (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Der Sinn eines 64Bit-Enums erschließt sich mir daher nicht.

Tarzan hat wieder zugeschlagen.
(die skurrilsten Technik Threads hier auf uc.net)

von 3? (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Zum statischen Testen von impliziten Annahmen kann man auch 
static_assert nehmen, bspw.
1
#include <assert.h>
2
// ...
3
static_assert(sizeof(enum foo) == 8, "hatte gedacht, der enum waere 8B gross?!");

in C++ auch ohne assert.h.

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Klingt nach DCF-77.

Es geht immer noch um mein Grafiksystem aus dem alten Thread:

Beitrag "Architektur Grafiksystem"

Da mir noch keine bessere Archtitektur eingefallen ist, werde ich jetzt 
mal den ersten Entwurf implementieren und mich von da aus zum 
nächstbesseren Entwurf hangeln.

Peter D. schrieb:
> Der Sinn eines 64Bit-Enums erschließt sich mir daher nicht.

Der Sinn besteht lediglich darin, innerhalb eines logischen Arrays 
möglichst bequem direkt mehrere Einträge verodern zu können.

von Walter T. (nicolas)


Bewertung
1 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Finde es selbst heraus, der sizeof -Operator dürfte Dir da helfen.

Hm. Auf die naheliegende Idee, den sizeof-Operator auf eine Konstante 
loszulassen, bin ich tatsächlich noch nie gekommen.

Also flugs ausprobiert:
1
enum
2
{
3
    e_test1 = 0x8000000080000000,
4
    e_test2 = 0x1,
5
};
6
7
enum
8
{
9
    e_test3 = 0x1,
10
};
11
12
void fkt(void)
13
{
14
15
    uint64_t test = e_test1;
16
    printf("\n Enum: %llx\n", test);
17
    switch( test )
18
    {
19
        case 0x8000000080000000:
20
            printf("Glück gehabt\n");
21
            break;
22
        default:
23
            printf("Pech gehabt\n");
24
    }
25
    printf("s1=%d, s2=%d, s3=%d\n", sizeof(e_test1), sizeof(e_test2), sizeof(e_test3));
26
}

Ausgabe unter Windows:
1
 Enum: 8000000080000000
2
Gl³ck gehabt
3
s1=8, s2=4, s3=4

Ausgabe auf dem LCD des STM32:
1
 Enum: 8000000080000000
2
Glück gehabt
3
s1=8, s2=4, s3=4

Irgendwie bin ich doch etwas überrascht, dass Konstanten überhaupt eine 
Breite haben. Dann bin ich noch überraschter, dass eine Konstante ohne 
Suffix eine größere Breite als Int hat, und dann bin ich noch 
überraschter, dass Kontanten innerhalb des gleichen Enums 
unterschiedliche Breiten haben können.

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Man kann das Verhalten über gcc Optionen beeinflussen.

> Dann bin ich noch überraschter, dass eine Konstante ohne
> Suffix eine größere Breite als Int hat

Bem ARM-GCC ist ein int 32bit (4 Bytes) groß.

> dass Kontanten innerhalb des gleichen Enums
> unterschiedliche Breiten haben können.

Das kommt mir auch komisch vor.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Walter T. schrieb:
> und dann bin ich noch überraschter, dass Kontanten innerhalb des
> gleichen Enums unterschiedliche Breiten haben können.

Wenn Du dem enum einen Typ verpasst (oder eine Variable vom Typ Deines 
enums anlegst), und sizeof darauf loslässt, solltest Du das größte 
Ergebnis bekommen.

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Wenn Du dem enum einen Typ verpasst [...] solltest Du das größte
> Ergebnis bekommen.

Verstehe ich nicht. Ändere ich das zu:
1
typedef enum test_e
2
{
3
    e_test1 = 0x8000000080000000,
4
    e_test2 = 0x1,
5
} test_t;
6
7
enum
8
{
9
    e_test3 = 0x1,
10
};
11
12
    printf("s1=%d, s2=%d, s3=%d\n", sizeof(e_test1), sizeof(e_test2), sizeof(e_test3));
13
    printf("enumsize = %d\n", sizeof( (test_t) e_test2) );
kommt beim ersten printf noch das gewohnte Ergebnis mit 
unterschiedlichen Größen heraus.

Rufus Τ. F. schrieb:
> (oder eine Variable vom Typ Deines
> enums anlegst)

Das ist klar. Zumindest, wenn man sich an den Gedanken gewöhnt, dass 
0x8000000080000000 aus irgendeinem Grund das Gleiche ist wie 
0x8000000080000000ULL.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Enum ist nur eine spezielle Art von Define. Der einzige Unterschied ist, 
daß Enums automatisch durchnummeriert werden. Nutzt man diese 
Eigenschaft nicht, dann kann man auch gleich Defines hinschreiben.
Daher ist auch klar, daß Enums immer die Breite haben, die durch 
Zahlenwert vorgegeben wird.
Als Typ hat ein Enum aber immer die Breite von int.
Mit -fshort-enums kann man die Breite verkleinern, z.B. auf 8Bit beim 
AVR-GCC. Da ich nie mehr als 256 Case benötige, reicht mir das aus.
Für Bitmasken nimmt man besser das _BV() Macro.

von c-hater (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:

> Enums nimmt man typisch für Aufzählungen und nicht für Bitmasken.

Das mag in C so sein, in vielen anderen Sprachen ist das nicht so. Da 
gibt es sogar extra-Qualifizierer für Flag-Enums oder sogar spezielle 
Mengen-Datentypen, deren Basis eben solche Flag-Enumerationen sind.

Nur weil C da ein wenig behindert ist, muss nicht die ganze restliche 
Welt die Beschränkungen dieses anachronistischen Geraffels als 
gottgegeben ansehen...

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
Ich würds nicht machen. Auch wenn
- der Code nie portiert werden muss
- die Wahrscheinlichkeit dass sich das Verhalten vom GCC ändert wohl 
recht klein ist
- niemand anderer den Code je anfassen wird
- usw. usf.
ist es trotz allem bad practice.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
c-hater schrieb:
> Das mag in C so sein, in vielen anderen Sprachen ist das nicht so.

Die Frage bezog sich aber doch auf C. Daher muß man das nicht in jedem 
Satz nochmal extra erwähnen.

von M.K. B. (mkbit)


Bewertung
0 lesenswert
nicht lesenswert
Walter T. schrieb:
> Ausgabe unter Windows: Enum: 8000000080000000
> Glück gehabt
> s1=8, s2=4, s3=4

Du lässt ja die Größe von den Konstanten ausgeben. Natürlich kann der 
Compiler da die Größe festlegen, die ihm am besten gefällt.
Wenn du eine Variable von deinem enum Typ anlegst und davon sizeof 
machst, dann sollte das Ergebnis wie erwartet sein.

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> c-hater schrieb:
>> Das mag in C so sein, in vielen anderen Sprachen ist das nicht so.
>
> Die Frage bezog sich aber doch auf C. Daher muß man das nicht in jedem
> Satz nochmal extra erwähnen.

Der c-hater muss das aber, so wie er es auch nicht lassen kann, dumme 
Schimpfwörter in jedem C Thread unterzubringen.

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
M.K. B. schrieb:
> Walter T. schrieb:
>> Ausgabe unter Windows: Enum: 8000000080000000
>> Glück gehabt
>> s1=8, s2=4, s3=4
>
> Du lässt ja die Größe von den Konstanten ausgeben. Natürlich kann der
> Compiler da die Größe festlegen, die ihm am besten gefällt.
> Wenn du eine Variable von deinem enum Typ anlegst und davon sizeof
> machst, dann sollte das Ergebnis wie erwartet sein.

https://godbolt.org/z/GP4fQR

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Enum ist nur eine spezielle Art von Define.

Aber eine fundamental verschiedene spezielle Form von #define, wenn man 
mehr betrachtet als die Möglichkeit, in globalem Rahmen lexikalische 
Konstanten zu definieren. Enum-Namen haben einen kontrollieren 
Gültigkeitsbereich, #defines nicht. Enums werden bei Deklaration 
berechnet, #defines bei Verwendung.

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
>> a) Wieso unterstützt der ARM-GCC 64 Bit breite Enums?
>
> Warum sollte er nicht? Sofern er int64_t kennt, d.h. 64-Bit-Werte
> überhaupt verarbeiten kann, würde ich das erwarten.

So blöd ist die Frage nicht. C11: "The expression that defines the value 
of an enumeration constant shall be an integer constant expression that 
has a value representable as an int."

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Als Typ hat ein Enum aber immer die Breite von int.

C11: "The choice of type is implementation-defined, ... An 
implementation may delay the choice of which integer type until all 
enumeration constants have been seen." (lies: optimierbar)

GCC: "Normally, the type is unsigned int if there are no negative values 
in the enumeration, otherwise int. If ‘-fshort-enums’ is specified, then 
if there are negative values it is the first of signed char, short and 
int that can represent all the values, otherwise it is the first of 
unsigned char, unsigned short and unsigned int that can represent all 
the values.

On some targets, ‘-fshort-enums’ is the default; this is determined by 
the ABI."

gcc -c -O -pedantic enum2.c
enum2.c:1:12: warning: ISO C restricts enumerator values to range of 
‘int’ [-pedantic]

: Bearbeitet durch User
von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Vincent H. schrieb:
> ist es trotz allem bad practice.

Ich wäre einer Variante besserer Praxis nicht abgeneigt. Den 
Anwendungsfall habe ich im vom mir verlinkten Thread ja recht 
ausführlich dargelegt.

Momentan implementiere ich tatsächlich diese "bad practice", um den 
Ansatz für Verbesserungen zu finden.

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
evtl. C++ nehmen, da kann man den Typ bei enums angeben.
Lasst doch den c-hater einfach stenkern, er wird seine Gründe haben

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.