mikrocontroller.net

Forum: Compiler & IDEs Wie verhält sich enum ++ beim Überlauf?


Autor: tecdroid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich hab ein programm, welches über enum den aktuellen menüzustand 
auswählen soll. weiterschalten mach ich einfach per ++ - operator, was 
zumindest keinen fehler wirft.
Was passiert jetzt aber, wenn ich über den letzten wert hinaus gehe? 
wird dann automatisch auf den ersten gesetzt oder hab ich einen 
überlauf?

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was soll das für einen Programmiersprache sein?

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> auf den ersten gesetzt oder hab ich einen überlauf?

Was ist der Unterschied?

Welche Programmiersprache?

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Was soll das für einen Programmiersprache sein?
Hmm, mal überlegen. GCC-Forum, ++-Operator...

Ich hab's: Delphi!

Zum Thema: In C ist ein enum nicht viel anderes als ein int.
Einer solchen Variablen kann ein Wert außerhalb des definierten
Bereichs zugewiesen werden. Geprüft wird da nichts.

In C++ ist ein Inkrement auf ein enum nur dann erlaubt wenn
der Operator explizit für diesen enum-Typ definiert wurde.

Auch folgendes geht in C++ nicht (in C dagegen schon):
enum uu { a, b, c};
uu = 1;

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
let wrote:
>
> enum uu { a, b, c};
> uu = 1;
> 

Was hat das für einen Sinn?

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Och nee, nicht wieder diese Sinnfragen.

Das hat überhaupt keinen Sinn. Es ist sozusagen vollkommen
sinnfrei. Diese Beispiel zeigt lediglich das der C-Compiler
hier (im Gegensatz zu C++) keine Typüberprüfung durchführt und
man einen enum wie einen int behandeln kann.

Aber das geht natürlich noch besser:
enum {x} i;
for (i = 0; i < 10; i++) puts("Hallo");

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also
int main(void)
{
  enum uu { a, b, c};
  uu = 1;

}

gibt bei mir den Fehler:
'main::uu' : no variable declared before '='

mit dem MS Visual C++ 2008 Compiler.

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
let wrote:
> ... Diese Beispiel zeigt lediglich das der C-Compiler
> hier (im Gegensatz zu C++) keine Typüberprüfung durchführt

Simon K. wrote:
> gibt bei mir den Fehler:
> 'main::uu' : no variable declared before '='
>
> mit dem MS Visual C++ 2008 Compiler.

was ja somit zu erwarten war...

BTW: der C-Compiler wird (vermutlich) eine Warnung ausgeben

Gruß
Roland

Autor: tecdroid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bei mir gabs keine warnung.
Heißt also, wenn ich nen ++ auf das enum mache, wirds evtl. irgendwann 
über die Grenzen der enumerierung hinausgehen? Dann muss ich das wohl 
abfangen :(
Langsam wirds eng auf dem 2313..
Weiß jemand, was ich da zur Optimierung alles tun kann? (okay- ist 
eigentlich nen anderes topic wert..)

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tecdroid wrote:
> Langsam wirds eng auf dem 2313..
> Weiß jemand, was ich da zur Optimierung alles tun kann? (okay- ist
> eigentlich nen anderes topic wert..)

Hallo,

also Deine Erwartungen sind etwas paradox: ob Du die Überlaufprüfung 
selbst programmieren musst oder ob der Compiler dies für Dich tut ändert 
nichts daran, daß eine gewisse Menge Code dafür notwendig sein wird.

Was sollte ein enum beim Überlauf tun ?
- Auf den 1. Wert springen ? Das kann an anderer Stelle genau falsch 
sein
- Eine Bluescreen ausgeben ? Wäre korrekt, ist aber für einen uC 
schwierig

Gruss,
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Roland Praml wrote:

> Simon K. wrote:
>> gibt bei mir den Fehler:
>> 'main::uu' : no variable declared before '='
>>
>> mit dem MS Visual C++ 2008 Compiler.
>
> was ja somit zu erwarten war...

Klar, weil das Beispiel syntaktisch falsch ist, nicht weil es
sematischer Unfug ist.

Das Beispiel deklariert im enum-Namensraum einen enum mit dem
Namen "uu", aber keine Variable namens "uu".

Richtig muss es sein:
int main(void)
{
  enum { a, b, c} uu;
  uu = 1;

}

> BTW: der C-Compiler wird (vermutlich) eine Warnung ausgeben

Bevor du irgendwas mutmaßt, nimmst du besser einen Compiler.  Der
GCC generiert eine Warnung, ja: "control reaches end of non-void
function".  Sonst nichts.  Hat er auch keinen Grund dazu.  (Das
"warum?" ist schon genannt worden: in C ist, anders als in C++, ein
enum nur eine andere Form des Typs "int".)

Autor: tecdroid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Herr Appelt für Deeeen Hinweis..
Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon 
im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tecdroid wrote:
> Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon
> im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..

Du wirst ja das enum nicht nur einfach so hinschreiben, sondern auch 
verwenden, z.B. in einem Switch. Und dann setzt Du es im letzten Case 
eben wieder auf 0, kostet 4 Byte.


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tecdroid wrote:
> Vielen Dank Herr Appelt für Deeeen Hinweis..
> Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon
> im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..

Ach?  Was meinst du, womit Compiler so kochen?

Das letzte Mal, als ich nachgesehen habe, war es jedenfalls auch nur
Wasser.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> tecdroid wrote:
>> Vielen Dank Herr Appelt für Deeeen Hinweis..
>> Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon
>> im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..
>
> Ach?  Was meinst du, womit Compiler so kochen?
>
> Das letzte Mal, als ich nachgesehen habe, war es jedenfalls auch nur
> Wasser.

Ich glaube, du hast ihn hier missverstanden. Es geht nicht darum, dass 
wenn der Compiler es macht, es effizienter wäre, sondern darum, dass es 
dann im aktuellen Code schon enthalten wäre. Die aktuelle Größe des 
Codes wäre also die Größe inklusive der Prüfung. Da man es aber selber 
machen muss, kommt der Code zum aktuellen Code noch hinzu.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:

> Da man es aber selber
> machen muss, kommt der Code zum aktuellen Code noch hinzu.

Es wird trotzdem nicht mehr Binärcode, eher weniger (wie Peter
dargelegt hat -- weil man die Prüfung u. U. sowieso in seiner
Applikation bereits vornehmen muss).

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Stefan Ernst wrote:
>
>> Da man es aber selber
>> machen muss, kommt der Code zum aktuellen Code noch hinzu.
>
> Es wird trotzdem nicht mehr Binärcode, eher weniger (wie Peter
> dargelegt hat -- weil man die Prüfung u. U. sowieso in seiner
> Applikation bereits vornehmen muss).

Du betrachtest es absolut, tecdroid meinte es aber relativ zur 
aktuellen Größe. Und aktuell ist anscheinend keine "manuelle" Prüfung 
drin.
Klar, es könnte natürlich auch sein, dass der Code durch hinzufügen der 
Prüfung kleiner wird, "größer" dürfte aber deutlich wahrscheinlicher 
sein.

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Richtig muss es sein:
>
> [c]
> int main(void)
> {
>   enum { a, b, c} uu;
>   uu = 1;
>
Hallo,

eben nicht, logisch würde man schreiben:

[c]
int main(void)
{
  enum { a, b, c} uu;
  uu = a;

tecdroid write:
>Vielen Dank Herr Appelt für Deeeen Hinweis..
>Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon
>im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..
>
Ich habe diese Diskussion zum Anlass genommen, mir ein blaues LCD zu 
bestellen. Dann kann ich endlich zum enum-Überlauf den Bluescreen 
auslösen.
Allerdings fehlt mit noch der dazu notwendige SW-Trap ;-)

Gruss,
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:

> Du betrachtest es absolut, tecdroid meinte es aber relativ zur
> aktuellen Größe. Und aktuell ist anscheinend keine "manuelle" Prüfung
> drin.

Der Punkt ist: um das gewünschte Überlaufverhalten zu erzeugen, muss
eine Prüfung drin sein.  Wenn sie der Compiler selbst einfügt, dann
wäre es der gleiche Aufwand wie für den Programmierer (der selbst dann
vorgenommen werden müsste, wenn der Programmierer genau weiß, dass die
Prüfung nicht nötig ist).

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

> Der Punkt ist: um das gewünschte Überlaufverhalten zu erzeugen, /muss/
> eine Prüfung drin sein.  Wenn sie der Compiler selbst einfügt, dann
> wäre es der gleiche Aufwand wie für den Programmierer (der selbst dann
> vorgenommen werden müsste, wenn der Programmierer genau weiß, dass die
> Prüfung nicht nötig ist).

Ja, das ist ja alles richtig.
Ich wollte dich doch nur darauf hinweisen (und ich bereue das längst), 
dass du den Post von tecdroid falsch verstanden hast.

> Würde nur der compiler dies selbst tun, dann wäre ja diese logik schon
> im binärcode enthalten- so gehen mal wieder 6-8 byte verloren..

Du hast das anscheinend so interpretiert:
"Wenn ich die Prüfungen von Hand machen muss, ist der Code größer, als 
wenn der Compiler selber automatische Prüfungen einfüg."

Gemeint war aber (so sehe ich das jedenfalls):
"Wenn der Compiler keine automatischen Prüfungen einfügt, dann sind im 
aktuellen Code auch noch gar keine Prüfungen enthalten. Ich muss sie 
also noch selber hinzufügen, was den Code nochmal etwas größer macht."
"Größer" im Vergleich zum aktuellen Zustand (also ganz ohne Prüfungen), 
nicht im Vergleich zur fiktiven Größe mit Compiler generierten 
Prüfungen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:

> Gemeint war aber (so sehe ich das jedenfalls):

Ich sehe, was du meinst.  Ob tecdroid das auch so meint, kann er uns
nächstes Jahr ja dann mal erklären...

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Der Punkt ist: um das gewünschte Überlaufverhalten zu erzeugen, /muss/
> eine Prüfung drin sein.  Wenn sie der Compiler selbst einfügt, dann
> wäre es der gleiche Aufwand wie für den Programmierer (der selbst dann
> vorgenommen werden müsste, wenn der Programmierer genau weiß, dass die
> Prüfung nicht nötig ist).

Hallo,

jetzt hab ich kapiert, wie die Frage gemeint war....

Trotzdem wundert mich, wie man diese Frage so stellen kann ohne auch zu 
erfragen, was der Compiler tatsächlich dann in dem Überlaufcode machen 
soll.

Z.B. compiler fügt code hinzu, der von max auf min springt

enum {mo, di, mi, do, fr, sa, so} tag;
for(tag=mo;tag<=so;tag++)

ergäbe eine Endlosschleife.
Selbst wenn er hier eine Sonderbehandlung durchführen würde, bei einer 
selbstprogrammierten Zählschleife mit while würde dies endlos laufen.

tag = mo;
while (tag <= so) tag++;

Ohne Overflow-Trap bzw. call einer optionalen Überlauf-Prozedur ist der 
Compiler für einen bildschirmlosen uC völlig hilflos.

Gruss,
Michael

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was Andres: Aufm AVR macht "enum" insofern wenig Sinn als solches, weils 
eben nen ganzen Integer verbraucht (wenn man nich den GCC generell auf 
ne andre Wortbreite umstellt).
enum bla_e {
a,
b,
c
}

enum bla_e variable; /* <-- braucht i.d.R. vier Bytes */

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Braucht auf dem AVR zwei Bytes (sizeof(int) == 2), aber man kann es
beim GCC (dessen Forum das ja hier ist) mittels __attribute__(packed)
auch auf ggf. ein Byte reduzieren.

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

interessante Fragen kommen mir da in den Sinn, geht nicht auch:

enum {a=1, b, c=5, d=7} x;
for (x=a, x<=d, x++) ....

Ist doch zur Laufzeit vemrutlich auch schwachfug, oder ?

Gruss,
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael Appelt wrote:

> Ist doch zur Laufzeit vemrutlich auch schwachfug, oder ?

So ist es.  Ein lückenhafter enum hat in C fast keinen Sinn (einziger
Unterschied zu lauter #defines ist, dass die Namen im Debugger
sichtbar sind).  Das kontinuierliche Durchlaufen aller Werte eines
solchen enum ist aber auf jeden Fall Schwachfug: entweder haben die
Zwischenwerte auch einen Sinn, dann hätte man sie im enum mit
aufzählen sollen, oder die Zwischenwerte sind witzlos, dann hat die
Schleife aber keinen Nährwert.

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Bindung der Konstanten des enum an die Variable wäre eine sinnvolle 
Prüfung durch den Compiler. Also Wert aus dem enum tag kann nicht einer 
variablen vom typ monat zugewiesen werden.

Nichmal das wird erkannt, oder ? Dafür mault doch sowieso ständig bei 
Zuweisung von signed nach unsigned etc.

Gruss,
Michael

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ein lückenhafter enum hat in C fast keinen Sinn

Vieleicht mal ein bisschen ueber den Tellerrand denken. Es gibt z.B. 
auch genuegend Faelle, wo die Werte vorgegeben sind, man aber trotzdem 
darueber iterieren moechte. Spontan fiele mir auch eine Menufunktion 
ein, wo natuerlich nicht jede Zeile besetzt sein muss, etc, pp.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael Appelt wrote:

> Nichmal das wird erkannt, oder ?

Es darf in C nicht erkannt werden.

Der C-Standard beschreibt, dass eine Aufzählungskonstante den Typ
"int" besitzt, und dass enum-Typen grundsätzlich kompatible zum
Typ "int" sind.

In C++ funktionieren enums übrigens wirklich etwa so, wie sich viele
das hier vorstellen.  In C sind sie nur eine Art Namen für Konstanten
vom Typ int.

> Dafür mault doch sowieso ständig bei
> Zuweisung von signed nach unsigned etc.

Macht er gar nicht, er warnt nur dann, wenn die Vorzeichenhaftigkeit
des Zieltyps eines Zeigers verschieden ist.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Stegemann wrote:

> Vieleicht mal ein bisschen ueber den Tellerrand denken. Es gibt z.B.
> auch genuegend Faelle, wo die Werte vorgegeben sind, man aber trotzdem
> darueber iterieren moechte. Spontan fiele mir auch eine Menufunktion
> ein, wo natuerlich nicht jede Zeile besetzt sein muss, etc, pp.

Entweder hat das dazwischen aber einen semantischen Zweck (auch wenn
es nicht besetzt ist), dann sollte es einen Namen bekommen, oder aber
es hat keinen, dann brauch ich auch nicht erst drüber iterieren.

Mir fällt jedenfalls nichts ein, wo das Sinn haben könnte.  In C++
kannste das schon irgendwie implementieren (da ja bereits geschrieben
wurde, dass du dann für die Implementierung deines ++-Operators selbst
zuständig bist), allerdings ist die Implementierung des Sprungs über
die Lücken dann ein Risiko, dass der ahnungslose Leser die Komplexität
der tatsächlich dahinterstehenden Operation nicht erwarten würde.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, aber vieleicht beschaeftigen sich hier manche schon zu lange nur 
noch mit Microcontrollern.

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ok, C++ ist inzwischen klar, da muss ich den Iterator selber 
implementieren.

Für lückenhaft indizierung bietet sich an:

const int index (7) = {1, 3, 5, 7, 11, 13, 17}

for (int i=0; i<7; i++)
   machwasmit(index(i));

In sowohl C als auch uCs sind ja für solche explizite Problemlösungen 
ausgelegt.

Gruss,
Michael

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Gedanke hinter C ist: "Vermeide unnütze Tests, damit der Code 
schlank und sauschnell ist."

D.h. wann immer der Compiler nicht einschätzen kann, ob ein Test nötig 
ist, überläßt er es dem Programmierer, die richtige und effektive Stelle 
zu finden.

Bei dem Enum wäre die richtige Stelle für den Test in dem letzten Case 
bzw. Default.
Soll der Compiler aber selber testen, müßte er es ja bei jeder Zuweisung 
machen, was den Code erheblich vergrößern würde.


Es gibt auch Stellen, wo man direkt froh ist, daß C einen nicht mit 
Tests gängelt, z.B. wenn man die Differenz zweier Zeitstempel bildet. Da 
muß man dann ein Überlaufen zulassen, damit die Differenz gültig ist.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Roland Praml wrote:
>
>> Simon K. wrote:
>>> gibt bei mir den Fehler:
>>> 'main::uu' : no variable declared before '='
>>>
>>> mit dem MS Visual C++ 2008 Compiler.
>>
>> was ja somit zu erwarten war...
>
> Klar, weil das Beispiel syntaktisch falsch ist, nicht weil es
> sematischer Unfug ist.
>
> Das Beispiel deklariert im enum-Namensraum einen enum mit dem
> Namen "uu", aber keine Variable namens "uu".

Danke. Darauf wollte ich hinaus. ;)

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.