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


von Walter T. (nicolas)


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)


Lesenswert?

enum class X : uint64_t { ...  };

ist das eine Option?

von Rufus Τ. F. (rufus) Benutzerseite


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)


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)


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)


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)


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)


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. (Gast)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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)


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)


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)


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)


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)


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)


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. (Gast)


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)


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)


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)


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)


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)


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)


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

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.