Forum: Mikrocontroller und Digitale Elektronik Enum oder #define?


von Horst S. (Gast)


Lesenswert?

Oh, oh, ich werde mal wieder gezwungen, Code von anderen Menschen zu 
lesen.

Gefunden in einem der wenigen AVR-kompatiblen Codeschnipseln zum VL53L1X 
(ich glaube, dieser Teil kommt ursprünglich von ST)
1
/** @defgroup VL53L1_define_DistanceModes_group Defines Distance modes
2
 *  Defines all possible Distance modes for the device
3
 *  @{
4
 */
5
6
typedef uint8_t VL53L1_DistanceModes;
7
8
#define VL53L1_DISTANCEMODE_SHORT             ((VL53L1_DistanceModes)  1)
9
#define VL53L1_DISTANCEMODE_MEDIUM            ((VL53L1_DistanceModes)  2)
10
#define VL53L1_DISTANCEMODE_LONG              ((VL53L1_DistanceModes)  3)
11
/** @} VL53L1_define_DistanceModes_group */
"VL53L1_DistanceModes" taucht als Parametertyp in einigen Funktionen 
wieder auf.

Find ich ungewohnt. Warum bauen die nicht einfach einen Enum drum?
1
typedef enum 
2
{
3
   VL53L1_DISTANCEMODE_SHORT = 1, 
4
   VL53L1_DISTANCEMODE_MEDIUM = 2,
5
   VL53L1_DISTANCEMODE_LONG = 3
6
} __attribute__ ((packed)) VL53L1_DistanceModes;
Liegt das jetzt daran, dass das packed-Attribut nicht auf allen Systemen 
den Byte-Datentyp garantiert?

von Peter D. (peda)


Lesenswert?

Horst S. schrieb:
> Liegt das jetzt daran, dass das packed-Attribut nicht auf allen Systemen
> den Byte-Datentyp garantiert?

Packed braucht man, wenn überhaupt, nur für Structs.
Enum war schon immer vom Typ int.

Enum ist auch nur eine andere Schreibweise für Defines von Konstanten. 
Der Vorteil ist, es zählt selber aufwärts, man kann also nicht 
versehentlich Defines doppelt vergeben.

von Anderer Frank (Gast)


Lesenswert?

Und sie sind typsicher.

von Bernd K. (prof7bit)


Lesenswert?

Anderer Frank schrieb:
> Und sie sind typsicher.

Aber leider nicht in C. Der einzige Vorteil ist daß enums 
selbstdokumentierend sind, man muß nicht herumrätseln um zu sehen welche 
Werte an der Stelle erwartet werden.

von Peter D. (peda)


Lesenswert?

Anderer Frank schrieb:
> Und sie sind typsicher.

In C ist da kein Unterschied, eine Konstante ist default auch vom Typ 
int.
Bei einem Define kann man allerdings einen anderen Typ spezifizieren, 
ein Enum bleibt immer signed int.

von Daniel V. (danvet)


Lesenswert?

Horst S. schrieb:

> typedef uint8_t VL53L1_DistanceModes;
>
> #define VL53L1_DISTANCEMODE_SHORT             ((VL53L1_DistanceModes) 1)
> #define VL53L1_DISTANCEMODE_MEDIUM            ((VL53L1_DistanceModes) 2)
> #define VL53L1_DISTANCEMODE_LONG              ((VL53L1_DistanceModes) 3)

Ehrlich gesagt habe ich so ein define (statt enum) noch nie gesehen.
Wie wird es denn dann eingesetzt? Vielleicht erklärt das, warum es kein 
enum ist.

von Peter D. (peda)


Lesenswert?

Daniel V. schrieb:
> Ehrlich gesagt habe ich so ein define (statt enum) noch nie gesehen.

Ist schon recht ungewöhnlich.
Wenn ich Typen definiere, kommt bei mir immer _t ans Ende.
Statt "(VL53L1_DistanceModes) 1" sollte "1U" eigentlich reichen.

von Cyblord -. (cyblord)


Lesenswert?

Ein Vorteil von enum ist dass es Teil der Kernsprache ist. Ein define 
ist lediglich Bestandteil des Präprozessors.

von Daniel V. (danvet)


Lesenswert?

Peter D. schrieb:
> Daniel V. schrieb:
>> Ehrlich gesagt habe ich so ein define (statt enum) noch nie gesehen.
>
> Ist schon recht ungewöhnlich.
> Wenn ich Typen definiere, kommt bei mir immer _t ans Ende.
> Statt "(VL53L1_DistanceModes) 1" sollte "1U" eigentlich reichen.

Die Unterschiede zwischen enum und #define sind mir bekannt.
Allerdings verstehe ich immer noch nicht den Einsatz des oben genannten 
#defines.
Wie kann ich das denn einsetzen?
Durch ein #define wird doch nur eine Textersetzung vorgenommen, und wenn 
dann irgendwo
1
...   ((VL53L1_DistanceModes) 1) ...

steht, was soll das bringen????

Deswegen meine Frage, wie werden die oben genannten Defines im Code 
konkret eingesetzt? Ich stehe auf dem Schlauch :-(

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Enum ist auch nur eine andere Schreibweise für Defines von Konstanten.

Das ist leider eben nicht so. C kennt keine echten Konstanten, nur 
Variablen die man nicht verändern darf ("const"). Makros ("#define") 
sind Textersetzungen und keine Konstanten.
Wenn man so etwas hat:
1
#define VL53L1_DISTANCEMODE_SHORT ((VL53L1_DistanceModes)  1)
2
// ... furchtbar viel Code ...
3
int main () {
4
  int VL53L1_DISTANCEMODE_SHORT = 7;
5
}
weil man nicht immer im Kopf hat welche Namen schon für Makros vergeben 
sind (insb. wenn man große Libraries verwendet welche Tausende davon 
definieren) gibt es lustige Compiler-Fehler. Hartgesottene 
C-Programmierer finden das in Ordnung weil Großbuchstaben nur für Makros 
vorenthalten sein sollen - das ist m.M.n. ein schlechter Schutz und auch 
nicht immer schön. Bei einer Konstanten oder einem enum passiert das 
nicht:
1
typedef enum 
2
{
3
   VL53L1_DISTANCEMODE_SHORT = 1, 
4
   VL53L1_DISTANCEMODE_MEDIUM = 2,
5
   VL53L1_DISTANCEMODE_LONG = 3
6
} VL53L1_DistanceModes;
7
// ... furchtbar viel Code ...
8
int main () {
9
  int VL53L1_DISTANCEMODE_SHORT = 7;
10
}
funktioniert. Daher sind enums und Konstanten soweit möglich zu 
bevorzugen. Konstanten kann man nur leider nicht z.B. als Array-Größen 
nutzen, weil sie  in C nicht Compile-Time-konstant sind (in C++ schon).

Immerhin wurde daran gedacht explizit den Typ VL53L1_DistanceModes mit 
anzugeben. Oft sieht man so etwas:
1
#define VL53L1_DISTANCEMODE_SHORT 1
2
3
void foo (VL53L1_DistanceModes) {}
4
void foo (int) {}
5
6
int main () {
7
  foo (VL53L1_DISTANCEMODE_SHORT);
8
}
Welche Funktion wird hier aufgerufen? Betrifft natürlich nur C++, C 
achtet nicht so auf Typen.

Ein Vorteil von Konstanten:
1
const VL53L1_DistanceModes VL53L1_DISTANCEMODE_SHORT = 1;
2
3
int main () {
4
  fwrite (&VL53L1_DISTANCEMODE_SHORT, sizeof (VL53L1_DISTANCEMODE_SHORT), 1, stdout);
5
}
geht weder mit enums noch Makros.

In C++ kann man es sich leicht machen und immer "const" nehmen. In C 
muss man zwischen enum und const abwägen und im Notfall kann man Makros 
nutzen.

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> typedef enum
> {
>    VL53L1_DISTANCEMODE_SHORT = 1,
>    VL53L1_DISTANCEMODE_MEDIUM = 2,
>    VL53L1_DISTANCEMODE_LONG = 3
> } VL53L1_DistanceModes;
> // ... furchtbar viel Code ...
> int main () {
>   int VL53L1_DISTANCEMODE_SHORT = 7;
> }funktioniert.

Gibt aber ne Warnung, ist also bad style:
enum.c:9: warning: declaration of 'VL53L1_DISTANCEMODE_SHORT' shadows a 
global declaration

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Gibt aber ne Warnung, ist also bad style:

Besser als kryptische Fehler dank Präprozessor. Und mit welchem Compiler 
und Optionen? Mein GCC gibt mit -Wall -Wextra -pedantic gar nix aus.

von Horst S. (Gast)


Lesenswert?

Daniel V. schrieb:
> Ehrlich gesagt habe ich so ein define (statt enum) noch nie gesehen.
> Wie wird es denn dann eingesetzt? Vielleicht erklärt das, warum es kein
> enum ist.

Die Konstanten beschreiben hier einen Registerinhalt des VL53L1X-Sensors 
(über I2C angesprochen). Ich denke mal, der Typedef von 
VL53L1_DistanceModes auf einen uint8_t stellt einfach nur den Byte-Typ 
sicher. (Man spart sich das Casten beim Schreiben auf's entsprechende 
TWI-Register).



Peter D. schrieb:
> Packed braucht man, wenn überhaupt, nur für Structs.
> Enum war schon immer vom Typ int.
Wenn ich einen Enum als packed deklariere, den wiederum in einer 
packed-Struktur verwende, ist das Feld 1 Byte groß, zumindest beim AVR.

Zitat aus der gcc-Doku 
(https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html)
"packed: This attribute, attached to an enum, struct, or union type 
definition, specified that the minimum required memory be used to 
represent the type."
Ob das IMMER ein Byte ist? Da schweigt die Doku.

von Daniel V. (danvet)


Lesenswert?

Ok

> #define VL53L1_DISTANCEMODE_SHORT             ((VL53L1_DistanceModes) 1)

soll ein Typecast sein, jetzt hab ich es geschnallt.
Die Lücke zur Zahl hat mich irritiert.

Insofern halte ich das #define für besser als das enum, weil man nicht 
noch zusätzlich casten muss, das ist schon "eingebaut".

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Und mit welchem Compiler
> und Optionen?

-Wshadow

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> -Wshadow

Na, die ist sonst aber nie an. Es gibt alle Möglichen 
-Wirgendwas-Optionen die einem bei praktisch jedem Code mit Warnungen 
überschütten... Deswegen alles umzubauen ist unpraktikabel. Shadowing 
ist schon okay, wenn man in einem lokalen Scope dann doch mal auf das 
globalere zugreifen will kann man das lokale immer noch umbenennen. Das 
tut dann nicht weh, und in allen anderen Fällen merkt man gar nichts und 
alles ist gut.

von Daniel V. (danvet)


Lesenswert?

Horst S. schrieb:
> Peter D. schrieb:
>> Packed braucht man, wenn überhaupt, nur für Structs.
>> Enum war schon immer vom Typ int.
> Wenn ich einen Enum als packed deklariere, den wiederum in einer
> packed-Struktur verwende, ist das Feld 1 Byte groß, zumindest beim AVR.

Es geht ja nicht allein um die Größe, es könnte ja auch ein sint8_t sein 
(oder in float oder...), dann haut das mit den enum (packed oder nicht) 
wieder nicht hin.

von Keiner N. (nichtgast)


Lesenswert?

Dr. Sommer schrieb:
> Immerhin wurde daran gedacht explizit den Typ VL53L1_DistanceModes mit
> anzugeben. Oft sieht man so etwas:
>
1
> #define VL53L1_DISTANCEMODE_SHORT 1
2
> 
3
> void foo (VL53L1_DistanceModes) {}
4
> void foo (int) {}
5
> 
6
> int main () {
7
>   foo (VL53L1_DISTANCEMODE_SHORT);
8
> }
> Welche Funktion wird hier aufgerufen? Betrifft natürlich nur C++, C
> achtet nicht so auf Typen.


Gar keine. Der Compiler meckert. In C gibts keine Funktionsüberladung.

von Dr. Sommer (Gast)


Lesenswert?

Keiner N. schrieb:
> Gar keine. Der Compiler meckert. In C gibts keine Funktionsüberladung.

Deswegen steht da ja auch "nur C++".

von Keiner N. (nichtgast)


Lesenswert?

Dr. Sommer schrieb:
> Keiner N. schrieb:
>> Gar keine. Der Compiler meckert. In C gibts keine Funktionsüberladung.
>
> Deswegen steht da ja auch "nur C++".

lies mal den ganzen Text bitte. Also den von Dr. Sommer

von DPA (Gast)


Lesenswert?

Ich verwende für sowas immer Enums. Ich kompiliere meinen Code auch 
immer mit "-std=c99 -Wall -Wextra -pedantic -Werror". Hat bei gcc 
folgende Vorteile:

 1) Der Compiler warnt, wenn man in einem Switch nicht entweder alle 
Optionen abdeckt, oder einen default case hat (-Wswitch): (mit 
-Wswitch-enum kann man ihn auch mit default case warnen lassen)
1
$ echo ' enum my_enum { A, B }; int main(){ enum my_enum e=A; switch(e){ case A:; } }' | gcc -x c -std=c99 -Wall -Wextra -pedantic -Werror -
2
<stdin>: In function main:
3
<stdin>:1:54: error: enumeration value B not handled in switch [-Werror=switch]
4
cc1: all warnings being treated as errors

 2) Der Compiler warnt beim Vergleich eines Enum mit einer Enum 
constante eines anderen Enums (-Wenum-compare)
1
echo ' enum my_enum { A, B }; enum my_enum_2 { C, D }; int main(){ enum my_enum e=A; (void)(e==C); }' | gcc -x c -std=c99 -Wall -Wextra -pedantic -Werror -
2
<stdin>: In function main:
3
<stdin>:1:88: error: comparison between enum my_enum and enum my_enum_2 [-Werror=enum-compare]
4
cc1: all warnings being treated as errors

Leider hat der gcc keine Option zum warnen bei Zuweisungen oder beim 
Vergleich 2er enum variablen, aber vielleicht kommt das ja noch. clang 
scheint dafür massenhaft Optionen zu haben, z.B. "-Wassign-enum". 
Ansonsten können auch viele linter vor derartigen Dingen warnen.

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Shadowing
> ist schon okay

Für mich nicht. Ist ne prima Methode, sich ins Knie zu schießen.
Für mich muß der gleiche Name auch immer die gleiche Bedeutung haben. 
Daher kann ich mich auch nicht mit der Überlagerung von C++ anfreunden. 
Blau muß immer blau bedeuten und rot immer rot.
Mir reicht die Mehrdeutigkeit in der menschlichen Sprache und die daraus 
entstehenden Mißverständnisse völlig. Das muß ich nicht auch noch bei 
ner Programmiersprache haben.

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Für mich nicht. Ist ne prima Methode, sich ins Knie zu schießen.

Was machst du dann, wenn du eine Library programmiert hast, die von 100 
Programmen genutzt wird, und du einen neuen Bezeichner hinzufügst? 
Prüfst du ob alle 100 Programme den nirgends nutzen?

Sowas hab ich total gern:
1
#include <stm32f4xx.h>
2
3
// Klasse zur Behandlung der RCC-Peripherie
4
class RCC { // <- Hier kryptische Fehlermeldung
5
};

von Cyblord -. (cyblord)


Lesenswert?

Dr. Sommer schrieb:
> Was machst du dann, wenn du eine Library programmiert hast, die von 100
> Programmen genutzt wird, und du einen neuen Bezeichner hinzufügst?
> Prüfst du ob alle 100 Programme den nirgends nutzen?

Peter programmiert nur in Kleinen. Gängige Softwarekonzepte sind im 
fremd und er lehnt diese grundsätzlich ab.

von Dr. Sommer (Gast)


Lesenswert?

z.B. bei der berühmten Entprellroutine:
1
int main(void) {
2
  const int i = 7;
3
  debounce( PINB, PB1); // Warnung bei -Wshadow
4
}
(i ist jetzt kein so seltener Bezeichner)

So explodiert alles:
1
#define i 42
2
int main(void) {
3
  debounce( PINB, PB1);
4
}

Da doch lieber "const int" und kein -Wshadow...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Packed braucht man, wenn überhaupt, nur für Structs.
> Enum war schon immer vom Typ int.

Falsch.  Bin ich erst neulich wieder drauf reingefallen.
1
enum ledstatus
2
{
3
    OFF, DIM, DIM_FLASH, FLASH, ON
4
} __attribute__((packed));
5
6
// ...
7
enum ledstatus leds[2 * NLEDS];
8
9
// ...
10
            // over temperature: flash-dim all LEDs
11
            memset(leds, DIM_FLASH, sizeof leds);

Das Ganze funktionierte ohne „__attribute__((packed))“ nicht wie
gewünscht (nur die Hälfte aller LEDs wurde passend gesetzt), mit
dagegen schon.

Das widerlegt ganz eindeutig deine Aussage: mit GCC und „packed“
passt ein enum in 8 Bit, sofern er hinreichend wenige Elemente
enthält.

Horst S. schrieb:
> Liegt das jetzt daran, dass das packed-Attribut nicht auf allen Systemen
> den Byte-Datentyp garantiert?

Anders: dieses Attribut ist eine Eigenheit des GCC; andere Compiler
können das entweder gar nicht, oder machen sowas vielleicht über ein
Pragma.

Insofern ist der Originalcode zumindest portabel.

Wenn ich weiß, dass ich eh' nur für den GCC schreibe, ist mir das
natürlich egal.

von DPA (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Was machst du dann, wenn du eine Library programmiert hast, die von 100
> Programmen genutzt wird, und du einen neuen Bezeichner hinzufügst?

Entweder der Bezeichner soll von anderen genutzt werden, dann stelle ich 
ein Prefix vor alle Bezeichner. Wäre zwar schön, wenn es Namespaces 
gäbe, aber man kann halt nicht alles haben. Andernfalls definiere ich es 
dort wo ich es brauche als static. Für gewisse dinge habe ich jenachdem 
auch Interfaces & Funktionen, mit denen ich Implementationsspezifische 
locale Instanzen registriere, die wiederum als static definiert wurden, 
so dass ich die Implementationen global nutzen kann, ohne ein 
zusätzliches Symbol einzuführen.

von Axel S. (a-za-z0-9)


Lesenswert?

Peter D. schrieb:
> Enum ist auch nur eine andere Schreibweise für Defines von Konstanten.

Nicht wirklich.

> Der Vorteil ist, es zählt selber aufwärts, man kann also nicht
> versehentlich Defines doppelt vergeben.

Das stimmt zwar, ist aber nicht der wesentliche Punkt. Bei ENUMs geht es 
explizit darum, daß es nicht interessiert, welcher Zahlenwert sich 
hinter den deklarierten Bezeichnern jeweils verbirgt. Weil jede 
Operation mit einer ENUM Variable entweder die Zuweisung oder der 
Vergleich mit einem der erlaubten Bezeichner ist. Alles andere ist in 
Verbindung mit ENUMs "bäh".

An dieser Stelle ist das aber gar nicht der Fall. Man will nicht nur 3 
verschiedene Fälle sicher unterscheiden, man will auch exakt die 
angegebenen Zahlenwerte dafür haben (mutmaßlich damit man sie in die 
entsprechenden Register schreiben kann; ich kenne diesen Sensor nicht im 
Detail). Und dann ist ein #define das Mittel der Wahl.

ENUM ist IMNSHO ein absolut überbewertetes Konzept.


Dr. Sommer schrieb:
> Wenn man so etwas hat:
> #define VL53L1_DISTANCEMODE_SHORT
> ((VL53L1_DistanceModes)  1)
> // ... furchtbar viel Code ...
> int main () {
>   int VL53L1_DISTANCEMODE_SHORT = 7;
> }
> weil man nicht immer im Kopf hat welche Namen schon für Makros
> vergeben sind

Das kann nicht passieren. Bezeichner in GROSSBUCHSTABEN sind immer 
Makros, niemals Variablen. Wer so schlampigen Code schreibt, bettelt 
geradezu um

> lustige Compiler-Fehler

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Axel S. schrieb:
> ENUM ist IMNSHO ein absolut überbewertetes Konzept.

Bei C++ funktionieren sie viel besser als bei C, wo sie historisch halt
nur eine Alternative zu "int" waren.  Dort sind sie dann wirklich
typsicher.

Früher war das wesentliche Argument für enum in C noch, dass der
Debugger dann die Namen auflösen kann; seit DWARF es schafft, dass
man auch die Definition von Makros in den Debuginformationen 
reflektieren
kann, ist dieser Vorteil jedoch passe.

von Dr. Sommer (Gast)


Lesenswert?

Axel S. schrieb:
> Bezeichner in GROSSBUCHSTABEN sind immer
> Makros, niemals Variablen.

Schwacher Schutz. In vernünftigen Sprachen kann man sich von 
Sprachmitteln statt von Schreib-Konventionen helfen lassen.

Axel S. schrieb:
> Wer so schlampigen Code schreibt
Wie würdest du denn eine Klasse oder Funktion nennen, die die 
"RCC"-Hardware behandelt? Überall in der Doku heißt das Teil "RCC". 
"Rcc"? "rCC"? "rcc"? "DiesIstKeinMakro_RCC"? Alles hässlich. Aber "RCC" 
ist leider vorbelegt von einem elenden Makro, und die kann man nicht 
shadowen.

von Bernd K. (prof7bit)


Lesenswert?

Axel S. schrieb:

> ENUM ist IMNSHO ein absolut überbewertetes Konzept.

Enum ist ein extrem nützliches Konzept in typsicheren Sprachen. Schau 
Dir nur mal an was zum Beispiel Sprachen wie Rust damit zuwege bringen 
können, die erschlagen damit auch gleich noch Nullpointer und 
Fehlerbehandlung mit einer Klappe!

Nur leider hatten die Erfinder von C ganz andere Prioritäten und auch 
diejenigen die all die Jahre den C Standard bis heute weitergepflegt 
haben hatten nie den Willen oder die Kraft die Karre mal ordentlich 
herumzureißen.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> z.B. bei der berühmten Entprellroutine:
> int main(void) {
>   const int i = 7;
>   debounce( PINB, PB1); // Warnung bei -Wshadow
> }(i ist jetzt kein so seltener Bezeichner)

Man kann sich vieles zusammen konstruieren.
i,j,k sind für mich als Schleifenzähler reserviert, das debounce-Macro 
macht aber nur in einer Endlosschleife ohne Schleifenzähler Sinn.
Daher kann ich ruhig -Wshadow drin lassen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> Nur leider hatten die Erfinder von C ganz andere Prioritäten

Vor allem: ganz andere Möglichkeiten.

64 KiB für Code und 64 KiB für Daten (sofern sie glücklich genug
waren, den Hack für "Split I&D" in ihrer PDP-11 nachgerüstet zu
haben).

> und auch
> diejenigen die all die Jahre den C Standard bis heute weitergepflegt
> haben hatten nie den Willen oder die Kraft die Karre mal ordentlich
> herumzureißen.

Es wäre halt inkompatibel geworden.  Daher konnte man das in C++ anders
durchsetzen.

Was man bei all dem Gemecker über deren Konzepte und den C-Standard
mal nicht vergessen sollte: wenn sich bei der Standardisierung
irgendwelche Informatiker durchgesetzt hätten, die „schöne Konzepte“
als Primat haben statt sinnvoller Rückwärtskompatibilität, dann wäre
C gewiss nicht auf der Position, auf der es sich heute befindet.

Dass man für Rückwärtskompatibilität Abstriche machen muss, dürfte 
völlig
außer Zweifel stehen.  So gesehen ist die fortlaufende Standardisierung
einer derartigen Sprache halt stets ein Spagat.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> i,j,k sind für mich als Schleifenzähler reserviert
1
      IMPLICIT INTEGER I-N

:-)

Allerdings halte ich das Argument dennoch für reichlich konstruiert;
wer
1
#define i <irgendwas>

schreibt, sollte nochmal zurück in die C-Grundschule gehen.

Dass C++ in vielerlei Hinsicht besser aufgestellt ist, dafür brauchen
wir hier nicht jedesmal einen Dr. Sommer … das war jedoch gar nicht die
Frage des TO.

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Man kann sich vieles zusammen konstruieren.
> i,j,k sind für mich als Schleifenzähler reserviert, das debounce-Macro
> macht aber nur in einer Endlosschleife ohne Schleifenzähler Sinn.

Na, man kann sich auch kuriose Regeln konstruieren! Und was ist mit 
"flag"? Das tritt natürlich im Zusammenhang mit debouncing auch nicht 
auf?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Na, man kann sich auch kuriose Regeln konstruieren!

Hör doch bitte einfach wieder auf mit deiner Missioniererei.  Sie passt
überhaupt nicht in diesen Thread.  Der TO wollte nämlich überhaupt nicht
wissen, ob das in anderen Sprachen anders, besser oder schlechter wäre –
nur, falls dir sein Anliegen entgangen sein sollte.

Dass man diverse Schwächen von C durch coding style guidelines
ausgleicht, ist einfach so.  Eine dieser völligen Grundregeln ist,
dass Makros immer GROSS geschrieben werden, Variablen nie.  Wenn man
sich an diese Regel hält, dann ist es wurscht, ob da nun "i" oder
"flag" steht: es ist eine Variable, kein Makro.

von Horst S. (Gast)


Lesenswert?

Ich fasse das mal für mich zusammen:

Wenn ich die Defines bei der Übernahme der Quellen im Controller zu 
Enums umschreibe, verliere ich keine Kompatibilität, wenn ich in den 
entsprechenden Funktionen den Cast einfüge. Unterm gcc läuft's auch 
nicht langsamer, weil der Schlauberger seine Typen kennt und den Cast 
uint8_t->uint8_t wegoptimiert?!?


Jörg W. schrieb:
> Der TO wollte nämlich überhaupt nicht
> wissen, ob das in anderen Sprachen anders, besser oder schlechter wäre –
> nur, falls dir sein Anliegen entgangen sein sollte.

Interpretier mich nicht. Ich hab da so meine Hintergedanken, die kannst 
Du doch noch gar nicht wissen :-)
Für die PC-Seite (C#) habe ich mittlerweile 'nen rudimentäres 
Übernahmetool, das mir aus den Enums und Strukturen des AVR-Projektes 
entsprechende Datentypen nebst Wandlungsroutinen für die Übertragung 
zusammenbastelt. Da stehen mir die Defines echt im Weg.

Wenn ich das also im Zusammenhang (Sensor/Controller/PC) betrachte, 
scheint mir bezüglich Kompatibilität eher der Enum der kleinste 
gemeinsame Nenner.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Horst S. schrieb:
> Für die PC-Seite (C#) habe ich mittlerweile 'nen rudimentäres
> Übernahmetool, das mir aus den Enums und Strukturen des AVR-Projektes
> entsprechende Datentypen nebst Wandlungsroutinen für die Übertragung
> zusammenbastelt.

In diesem Falle bist du doch sowieso komplett Abhängig von den
Implementierungsdetails der jeweiligen Systeme. Da spielt die
Portabilität des Originalcodes keine große Geige.

> Interpretier mich nicht.

Wenn du Hintergedanken hast, die über deine initiale Frage hinausgehen,
wäre es natürlich sinnvoll, diese gleich in der Frage mit zu erwähnen.

von Horst S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Wenn du Hintergedanken hast, die über deine initiale Frage hinausgehen,
> wäre es natürlich sinnvoll, diese gleich in der Frage mit zu erwähnen.

Die eigentliche Frage (ist mir auch erst im Verlauf des Threads 
aufgegangen)
"Sind Enums über Systemgrenzen hinweg überhaupt zu gebrauchen"
hab ich mir, ehrlich gesagt, nie gestellt. Wenn doch, hätte ich spontan 
geantwortet: "Natürlich!"
Allerdings auch nur mit dem Wissen, dass einem Element ein Wert 
zugewiesen werden kann (in diesem Fall muss). Wer das nicht tut, hat 
noch nie einen Kollegen gehabt, der die Elemente eines Enums mit Genuss 
alphabetisch sortiert (und neue Elemente auch mal in der Mitte einfügt).

Das ist ein Vertrag, der dem #define-Makro in nichts nachsteht.

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.