Wie benennt ihr eure Variablen eindeutig in der Programmiersprache C
damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine
bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Joern DK7JB .. schrieb:> Wie benennt ihr eure Variablen eindeutig in der Programmiersprache C> damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine> bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Nur Anfänger kommen überhaupt auf die Idee, sich um solchen völlig
unwichtigen Scheiss irgendwelche Gedanken zu machen. Damit du es
begreifst: es spielt absolut kein Rolle, welchen Namen ein Symbol trägt.
Wichtig ist allein, dass sinnvoll dokumentiert ist, was es
repräsentiert.
Na klar: wenn man kann, wählt man Namen, die die wenigstens die halbe
Dokumentation darstellen. Der Datentyp muss dabei allerdings nicht
unbedingt erwähnt werden. Richtige Programiersprachen meckern nämlich
sowieso, wenn man sich da vergreift...
Der Typ ist eindeutig, egal, wie die Variable heißt.
Manche Leute benutzen eine Konvention, daß sie im Variablennamen den Typ
codieren, am verbreitetsten ist die "ungarische" Notation mit
vorangestellten Kürzeln wie z.B. einem kleinen "p" zur Kennzeichnung
eines Pointers, ein "i" für Kennzeichnung eines Ints etc.
"Ungarisch" heißt diese Konvention, weil sie von Charles Simonyi
entwickelt wurde (der aus Ungarn kommt und eine Zeitlang bei Microsoft
gearbeitet hat).
https://en.wikipedia.org/wiki/Charles_Simonyihttps://en.wikipedia.org/wiki/Hungarian_notation
Eine weitere Konvention aus ähnlichem Dunstkreis ist "CamelCase", bei
dem Variablennamen, die aus mehreren Wörtern zusammengesetzt werden, mit
Großbuchstaben im Wort geschrieben werden - der Gegenentwurf ist die
Verwendung von Unterstrichen:
MeineVariableIstSchoen
meine_variable_ist_schoen
Ersteres mit der ungarischen Konvention gepaart kann dann so aussehen:
1
pstrMeineVariableIstSchoen="Bla";
2
dwMeineVariableIstSchoen=0xFFEEDDCC;
3
iMeineVariableIstSchoen=6;
4
dblMeineVariableIstSchoen=12.34E4;
Wie gesagt, das liegt im Auge des Betrachters.
Wirklich wichtig ist es aber, die einmal gefundene Konvention
konsequent beizubehalten oder wieder abzuschaffen, aber niemals
mehrere Konventionen, gar konträre, miteinander zu mischen.
Ja, da halte ich doch gleich mal dagegen, daß ich es sehr praktisch
finde, wenn ich mich um solchen Mist nur da kümmern muß wo ich es auch
wirklich brauche.
$x=1234;
$x="Ach nee besser doch nicht.";
$x=(int)$x; wenns denn sein muß.
Rufus Τ. F. schrieb:> pstrMeineVariableIstSchoen = "Bla";> dwMeineVariableIstSchoen = 0xFFEEDDCC;> iMeineVariableIstSchoen = 6;> dblMeineVariableIstSchoen = 12.34E4;
Schöne Beispiel :)
Meine Erfahrungen:
Falls Konventionen genutzt werden, sind diese meist angelehnt an die
Ungarische Notation mit individuellen Erweiterungen.
Weiteres Beispiel:
Es wird nicht nur der Typ, sondern auch der Gültigkeitsbereich dem Namen
voran gestellt:
lokal: blMeineVariableIstSchoen = 6; // Byte lokal
global: bgMeineVariableIstSchoen = 6; // Byte global
main: bmMeineVariableIstSchoen = 6; // Byte innerhalb Main
kenny schrieb:> lokal: blMeineVariableIstSchoen = 6; // Byte lokal>> global: bgMeineVariableIstSchoen = 6; // Byte global>> main: bmMeineVariableIstSchoen = 6; // Byte innerhalb Main
Das ist ja super. Da könnte man ja sogar noch die Zeilennummern mit rein
kodieren und den Dateinamen. Dann bräuchte man sich um einen sinnvollen
prägnanten Namen keine Gedanken mehr machen.
Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit
"gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden
Variablennamen gab:
a
aa
aaa
aaaa
aaaaa
Joern DK7JB .. schrieb:> Wie benennt ihr eure Variablen eindeutig in der Programmiersprache> C> damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine> bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Das hängt von der im Betrieb eingeführten Konvention ab. Profis
gestalten ihren Code vor allem inheitlich und dazu gehört eben auch die
Variablen vernünftig zu benennen. Die ungarische Notation empfinde ich
als sehr sinnvoll. Man erkennt Code von Anfängern oder Schluderern
daran, dass die Variablennamen und die gesamte Gestaltung des Codes
unleserlich und schwer zu verstehen ist. Hier spielen auch Kommentare
und optische Strukturierung eine Rolle (ist ein anderes Thema, lässt
sich aber ebenfalls unter dieses Thema subsummieren).
Rufus Τ. F. schrieb:> Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit> "gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden> Variablennamen gab:>> a> aa> aaa> aaaa> aaaaa
Selbst das könnte unter gewissen Umständen einen Sinn ergeben.
Allerdings: Es ist doch sehr stark anzunehmen: Es ergibt keinen.
In Projekten an denen ich arbeite ist die einzig übliche Notation
typischerweise das m_-Präfix vor Membervariablen, um die Namenskollision
mit einem Getter zu vermeiden. Andere Präfixe werden nicht benutzt, und
ich halte sie auch nicht für hilfreich.
c-hater schrieb:> Nur Anfänger kommen überhaupt auf die Idee, sich um solchen völlig> unwichtigen Scheiss irgendwelche Gedanken zu machen. Damit du es> begreifst: es spielt absolut kein Rolle, welchen Namen ein Symbol trägt.> Wichtig ist allein, dass sinnvoll dokumentiert ist, was es> repräsentiert.
Es spielt also "absolut kein Rolle", welchen Namen ein Symbol trägt. Na
denn, wenn du das meinst. Bisher war ich der Meinung, dass nur Pfuscher
eine solche Meinung haben können.
Ich deklariere nur die Grundtypen per Prefix
f für Flag (Bool, Ja/Nein, 1/0)
i für Ganzzahl (int, long int)
j für Fließkoma
c für char (im Sinne eines einzelnen Zeichens)
s für String
p für Pointer
Andere halten sich strikt an die ungarische Konvention.
In Projekten muss man sich an die Projektvorgaben halten. Das sind aber
auch nicht immer dieselben.
Um Bösartigkeiten in Projekten (ausbleibende Zahlung) präventiv zu
"beantworten", lassen sich Namen auf das funktionell Notwendige
reduzieren. O0O0OO00 (Mischung aus 'O's und Nullen), IlIl1lII1,
a010100001000001, a010100000100001, a001100000100001. Viele Spaß wünscht
man dem Nachfolger, der das Projekt pflegen muss.
Es ist mir aber noch nie passiert, dass ich sowas tun musste. Allerdings
sind die Zeiten härter geworden, und extrem assozial. Gell C-Hater, du
weißt das auch ;)
Rufus Τ. F. schrieb:> Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit> "gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden> Variablennamen gab:>> a> aa> aaa> aaaa> aaaaa
Ein Kollege nannte seine Funktionen gerne step1(), step2(), step3() und
so weiter. Als er dann mal eine Funktion einfügen sollte, nannte er sie
step2b(). Er war davon überzeugt, dass das viel besser sei, als normale
sprechende Namen, weil man so ihre Aufruf-Reihenfolge ablesen kann.
Wegen seiner Weigerung, das zu unterlassen, wurde er zum ex-Kollegen.
El Helicoide schrieb:> c-hater schrieb:>> Nur Anfänger kommen überhaupt auf die Idee, sich um solchen völlig>> unwichtigen Scheiss irgendwelche Gedanken zu machen. Damit du es>> begreifst: es spielt absolut kein Rolle, welchen Namen ein Symbol>> trägt.>> Es spielt also "absolut kein Rolle", welchen Namen ein Symbol trägt.
Tja. Ich hätte nie gedacht, daß ich das mal sage, aber wo er Recht hat,
hat er Recht.
Namen von Symbolen sollten vor allem aussagekräftig für den Menschen
sein, der den Code lesen und pflegen muß. Der Typ ist dafür in 99.9% der
Fälle aber vollkommen irrelevant bzw. wenn erforderlich, von der IDE
mit nur einem Tastendruck abrufbar ("zeige die Definition des Symbols
unter der Maus").
Darüber hinaus halte ich es für höchst problematisch, wenn es
Variablen mit gleichem "Grundnamen", aber verschiedenem Typ gibt. Also
bspw.
1
pstrMeineVariableIstSchoen="Bla";
2
dwMeineVariableIstSchoen=0xFFEEDDCC;
3
iMeineVariableIstSchoen=6;
4
...
wie weiter oben im Thread gesehen. Es gibt also genau gar keinen
Grund, den Typ irgendwie in den Variablennamen aufzunehmen. Deswegen
habe ich mich ungarischer Notation und ähnlichem Unsinn auch immer
strikt verweigert. Probleme hatte ich damit übrigens noch nie, denn ich
habe auch noch keinen ernstzunehmenden Programmierer getroffen, der auf
ungarischer Notation bestanden hätte.
> Bisher war ich der Meinung, dass nur Pfuscher> eine solche Meinung haben können.
Mit derartigen Ausfälligkeiten diskreditierst du dich nur selber.
Das Thema wurde hier im Forum schon sehr oft diskutiert. Hier sind zwei
Beispiele für recht lange Threads mit entsprechend vielen verschiedenen
Meinungen:
Beitrag "Notation (Ungarische Notation)"Beitrag "Typpräfixe im Programmcode"
Meine Meinung: Die Kodierung des Typs in Variablennamen
- ist unnötig (beim Durchlesen von Programmcode interessiert der
Variablentyp nur selten und wenn doch, ist er schnell anderweitig
auffindbar),
- bringt einige Nachteile mit sich (flüssiges Lesen wird erschwert, nach
einer Änderung des Typs müssen alle Vorkommen der Variable geändert
werden) und
- eine konsequente Umsetzung ist ohnehin nicht praktikabel (bei
selbstdefinierten Typen reicht ein Präfix aus 1 oder 2 Zeichen zur
Typidentifikation nicht aus, und bei Funktionsnamen, wo zum Gesamttyp
sowohl der Rückgabetyp als auch die Typen sämtlicher Argumente
gehören, hört der Spaß endgültig auf).
Ganz abgesehen davon entspricht die Microsoftsche Ungarische Notation
nicht den ursprünglichen Ideen ihres Erfinders Simonyi. Zudem hat auch
Microsoft längst den Unsinn darin erkannt und verbietet mittlerweile (in
.NET-Bibliotheken) sogar ihre Nutzung.
Rufus Τ. F. schrieb:> Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit> "gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden> Variablennamen gab:>> a> aa> aaa> aaaa> aaaaa
Vieleicht war das ein skalierbares Programm zum Batterie testen ;-)
Stefanus F. schrieb:> Ein Kollege nannte seine Funktionen gerne step1(), step2(), step3() und> so weiter. Als er dann mal eine Funktion einfügen sollte, nannte er sie> step2b(). Er war davon überzeugt, dass das viel besser sei, als normale> sprechende Namen, weil man so ihre Aufruf-Reihenfolge ablesen kann.
Ich finde diese Idee in manchen Kontexten (z.B. Handler in State
Machines) gar nicht sooo verkehrt - aber unter der Voraussetzung dass
der Indizierungspräfix den Kontext identifiziert und dass die einzelnen
Steps auch noch einen semantischen Namensteil haben. Fiktives Beispiel
1
xfer00_Init
2
xfer01_SendRequest
3
xfer03_OnResponse
Ohne die Indizierung der Funktionen wäre sonst aus dem Code nur schwer
ersichtlich in welcher Reihenfolge sie geplant waren.
Ansonsten halte ich nur in Ausnahmefällen es für sinnvoll übers Knie
gebrochen den Typen in den Variablennamen hinen zu kodieren. Jede
moderne IDE zeigt den einem genau so gut per Tooltip o.ä. an. Ungarische
Notation bringt keinen Nutzwert, erwschwert nur das Lesen. Ausnahme
wären wenn beispielsweise bei Konvertierungen inhaltlich gleiche Daten
in unterschiedlichen Formaten vorliegen:
Moin,
Wie waers denn mit: Programmiersprache wechseln?
Es gibt Programmiersprachen, wo man sich ueber Variablennamen keine
Gedanken machen muss - da heissen die einfach: r0..r31 oder a,x,y oder
a,f,b,c,d,e,h,l... ;-D
Gruss
WK
Yalu X. schrieb:> Meine Meinung: Die Kodierung des Typs in Variablennamen> - ist unnötig (beim Durchlesen von Programmcode interessiert der> Variablentyp nur selten und wenn doch, ist er schnell anderweitig> auffindbar),
In Pascal stellt man bei Typ- und Klassenbezeichnern gerne ein "T" vorne
ran, um zu kennzeichnen, dass es keine Variable ist. Bei C++ verwendet
man da ja gern Groß- und Kleinschreibung, da gefällt mir die
Präfixvariante deutlich besser.
In den seltenen Fällen wo ich Pointer verwende stelle ich ein "p" vorne
an, quasi als Warnblinkanlage, dass ich bei dieser Variablen besonders
aufpassen muss.
Bei C-Programmen ist das eigentlich eine unsinnige Sache (wird ja auch
im entsprechenden Wikipedia-Artikel zur Ungarischen Notation mit einigen
Zitaten ziemlich zerrissen).
Ich programmiere jedoch viel in Assembler für MSP430 und da hilft mir
folgende Konvention für Präfixe:
signed uns. Bedeutung
------------------------------------------------------
8 bit b c "Byte" bzw. "Character"
16 bit s w "Short" bzw. "Word"
32 bit i q "Integer" bzw. "Quad Byte"
64 bit l o "Long long" bzw. "Octo Byte"
"q" für "Quad Word" statt "dw", damit ich das Präfix auf 1 Zeichen
limitieren kann, dasselbe bei 64 bit. Ist es ein Array, dann wird "a"
davorgesetzt, bei Zeigern "p"; ergibt dann z.B. "ac" für einen String
oder "pas" als Zeiger auf ein Array von signed 16-bit-Werten.
Weiters sind die Funktionen in entsprechenden Modulen untergebracht, die
typischerweise mit 3 bis max. 5 Zeichen abgekürzt werden, gefolgt von
einem Unterstrich und dem eigentlichen Variablennamen, also z.B.
"wPwr_BatVlt" oder "wPwr_UsbVlt" (unsigned 16 bit-Wert im Power-Modul,
enthält Batterie/USB-Spannungswert) oder "sPwr_SysTmp" (signed 16 bit
Systemtemperatur).
Dergute W. schrieb:> Es gibt Programmiersprachen, wo man sich ueber Variablennamen keine> Gedanken machen muss - da heissen die einfach: r0..r31 oder a,x,y oder> a,f,b,c,d,e,h,l... ;-D
Assembler ist keine Programmiersprache.
Ich musste auch schon an Code arbeiten, der einen solchen Coding Style
hatte:
Präfixe
-------
g: global
a: array
st: struct
Da gab es dann ein globales array aus structs, das dann
"gastReceivedMessages" hieß.
Meine Meinung: Absoluter Murks. Nie den typen in den Namen schreiben.
Wenn du nicht weißt, was eine Variable ist, solltest du dir überlegen,
ob du da überhaupt rumcoden solltest.
Die Lesbarkeit von Code hat absoluten Vorrang. Code wird mal grob
geschätzt zu über 80% gelesen und zu 20% geschrieben. Und eine solchen
Variablenbenamung ist nicht leserlich.
Auch der übermäßige Gebrauch von typedefs ist eine Katastrophe. Die
einzigen Dinge, die sinnvoll sind, sind uintX_t und solche Sachen. Das
ist wenigstens halbwegs transparent. Aber eine struct würde ich nur
typedef-en, wenn alle Zugriffe darauf komplett über Funktionen
abstrahiert sind. So wie zum Beispiel der FILE Typ aus stdio.h. Darauf
wird nur mit fopen() etc. zugegriffen.
Aus diesem Grund ist IMHO C++ schon inhärent kaputt, weil die
Deklaration einer struct von Haus auch ein typedef auf denselben Namen
verursacht.
M. H. schrieb:> Auch der übermäßige Gebrauch von typedefs ist eine Katastrophe.
Erlaubt aber später, den darunterliegenden Typ abzuändern. Klassisches
Beispiel ist "time_t" - das kann man auf 64bit abändern um Zeiten nach
2038 abbilden zu können. Gleiches gilt für mode_t, off_t usw. Das hilft
auch bei der Selbst-Dokumentation des Codes: Eine Funktion "writefile
(int, unsigned int, unsigned int)" ist nicht so durchsichtig. Mit
Parametertypen "FILE*, mode_t, off_t" kann man schon erraten worum es
geht.
C++ Metaprogrammierung wäre ohne typedef gar nicht erst möglich. Da wird
das intensiv genutzt.
M. H. schrieb:> Aus diesem Grund ist IMHO C++ schon inhärent kaputt, weil die> Deklaration einer struct von Haus auch ein typedef auf denselben Namen> verursacht.
Es wird kein typedef (Alias) definiert. C++ hat überhaupt keine structs,
"struct" definiert Klassen, und die kann man direkt nutzen, ohne
"struct" oder "class" davor. Es ist übrigens Absicht, dass man einem
Typ nicht direkt ansieht, ob er jetzt ein Klasse, enum oder Alias ist -
das ist ein Abstraktionsmechanismus. Alle Typen werden so einheitlich
wie möglich behandelt.
Dr. Sommer schrieb:> Es wird kein typedef (Alias) definiert. C++ hat überhaupt keine structs
Na klar hat C++ structs:
http://www.cplusplus.com/doc/tutorial/structures/
Und in dem Beispiel dort sieht man auch gleich das von mir angesprochene
Typedef verhalten. Hat man eine Struktur namens "foo", kann man sie
entweder mit struct foo bar; instantiieren oder mit foo bar;.
M. H. schrieb:> Na klar hat C++ structs:> http://www.cplusplus.com/doc/tutorial/structures/
cplusplus.com ist keine Referenz. Da steht viel Unsinn. C++ hat keine
Structs, nur Klassen. Das Schlüsselwort "struct" definiert eine
Klasse, in der per default alles "public" ist. Siehe z.B.:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
S. 238:
> Members of a class defined with the keyword class are private by default.> Members of a class (!) defined with the keywords struct (!) or union> are public by default.
Und S. 211:
class-key: class struct union
https://stackoverflow.com/a/34108140> In fact, C++ has not had structs since 1985. It only has classes.
Und wie gesagt wird kein Alias definiert. Eine Klasse ist direkt ohne
"struct" oder "class" davor zugänglich. Es wird einfach nicht gebraucht.
1
structA{intx;};
ist in C++ das gleiche wie
1
classA{
2
public:
3
intx;
4
};
Und Klassen sind nun einmal direkt zugänglich, wie eben hier per "A";
"class A" ist redundant (und hässlich).
Code, welcher einen Typ nutzt, soll unabhängig davon sein, ob das jetzt
eine Klasse, enum oder built-in Typ ist. Wenn ich immer "enum Mode m"
schreibe, kann ich aus "Mode" keine Klasse mehr machen, wenn das nötig
werden sollte. Wenn ich nur "Mode m" schreibe, geht das.
Dr. Sommer schrieb:> C++ hat /keine/> Structs, nur Klassen. Das Schlüsselwort "struct" definiert eine> Klasse, in der per default alles "public" ist.
Genau das ist der Unterschied zwischen struct und class: die
Sichtbarkeit der Member, wenn sie nicht explizit angegeben wird. Und
weil es einen Unterschied gibt, gibt es eben sehr wohl beides in C++.
struct und class sind nicht eben nicht ganz synonym.
Thomas M. schrieb:> Und> weil es einen Unterschied gibt, gibt es eben sehr wohl beides in C++.
Wenn aber "struct" eine Klasse definiert (siehe das Zitat), wie
definiert man dann structs?
c-hater schrieb:> Damit du es> begreifst: es spielt absolut kein Rolle, welchen Namen ein Symbol trägt.> Wichtig ist allein, dass sinnvoll dokumentiert ist, was es> repräsentiert.
Das erklärt vielleicht Deine mir unbegreifliche Abneigung von C
gegenüber Assembler. Und es ist einfach falsch.
Eine sinnvolle, intuitive bzw. den Projekt/Firmen-Gepflogenheiten
entsprechende Benamung ist weit hilfreicher als eine Dokumentation.
Neben den zu vernachlässigenden Schlüsselworten in C (und nur um C
geht's in diesem Thread), erschaffen die gewählten Namen eines Projekts
(oder einer Codebasis) ein sprachliches Universum, dessen
Verständlichkeit / Nutzbarkeit mit den Benennungen steht und fällt.
Jeder Mensch ist sehr erfahren in natürlicher Sprache. Und genauso wie
Wortneuschöpfungen dort gewissen intuitiven Regeln unterliegen, sollten
sich diese auch in Projekten/Firmen entwickeln. Wenn es ein Verb
"kongen" gibt, dann gibt es naheliegende Assoziationen mit "Konger",
"gekongelt" oder "KongTreff". Weil man Konventionen folgt. Und je besser
man das tut, umso lesbarer wird Prosa. Das gleich gilt für Quelltexte.
Was der Mensch allerdings weniger kann, ist Muster in Buchstaben oder
Ziffern-Kombinationen zu "lesen". Präfixe a la pcav für pointer auf char
Array volatile oder so sind oft ärgerlich. Genauso wie Lange
"Selbsterklärende" Namen. Wenn jemand Annegret Kramp Karrenbauer heißt,
ist AKK das kleinere Übel. Und auch ein
DonauDampschiffahrtsFregattenVizeKapitän wird, wenn man das öfter
auftaucht eine glücklichere Bezeichnung finden.
Thomas M. schrieb:> Dr. Sommer schrieb:>> C++ hat /keine/>> Structs, nur Klassen. Das Schlüsselwort "struct" definiert eine>> Klasse, in der per default alles "public" ist.>> Genau das ist der Unterschied zwischen struct und class: die> Sichtbarkeit der Member, wenn sie nicht explizit angegeben wird.> Und weil es einen Unterschied gibt, gibt es eben sehr wohl beides in C++.
Es gibt beide Schlüsselwörter, aber das dahinterstehende Konstrukt ist
das selbe. Ich kann von einer Klasse ableiten, ihr Memberfunktionen
(auch virtuelle) geben, Elemente private machen u.s.w., und das ist
völlig unabhängig davon, ob ich es mit dem Schlüsselwort "class" oder
dem Schlüsselwort "struct" definiert habe. Mit "struct" definiert man in
C++ also nicht das, was in C eine struct wäre, sondern eine Klasse, mit
allen Features, die es für Klassen in C++ gibt.
Die Schlüsselworte "struct" und "class" sind hier überflüssig, der Typ
heißt einfach nur "my_struct".
Direkt austauschbar sind struct und class nicht; der Unterschied ist die
standardmäßige Zuordnung zu public bzw. private.
Nachdem ich mich schweren Herzens von meinem VB6 (Visual Basic)
verabschiedet habe, habe ich mich für Python unter Ubuntu entschieden.
Trotz rudimentärer Kenntnisse in C, denn in Py definierst du eine
Variable und der wird ein "passender" Typ zugeordnet. Wenn man die
Variable explizit typisiert, dann steht es ja da und muß nicht noch im
Namen erscheinen. Das scheint mir in C doch ähnlich und deshalb macht
sich der TO wohl unnötige Sorgen...und wenn ich den Typ wissen will,
dann schau ich in der IDE im Quellcode nach und weiß ihn sofort. Wenn
ich ein fremdes Skript verstehen will, dann ist mir der Typ der Variable
doch erst mal egal. Erst wenn ich bei der Ausführung auf Probleme
stosse, dann wird mich vielleicht auch der Typ interessieren. Und dann
gibt der Compiler in der Regel die entsprechenden Hinweise! Z.B.
"Funktion in Zeile xyz erwartet ein Array" oder "erwartet 3 Argumente,
hat 2". Das alles kann man durch eine entsprechende Benennung doch nicht
verhindern. Deshalb wähle ich meine Bezeichnungen immer nach der
Funktion. Also test_dat_in oder norm-matrix....
Gruß Rainer
Rufus Τ. F. schrieb:> Direkt austauschbar sind struct und class nicht; der Unterschied ist die> standardmäßige Zuordnung zu public bzw. private.
Und dass man "class" bei Templates für Typ-Parameter verwenden kann,
struct nicht.
a_zip schrieb:> Trotz rudimentärer Kenntnisse in C, denn in Py definierst du eine> Variable und der wird ein "passender" Typ zugeordnet.
In Python definiert man Variablen nicht. Man weist einfach was zu, und
wenn sie noch nicht existiert, wird sie dann erzeugt. Und sie bekommt
dann einfach den Typ, den die rechte Seite der Zuweisung hatte. Und bei
der nächsten Zuweisung wieder. Nachteil ist, dass die Variable munter
ihren Typ wechseln kann, ohne dass das an der Stelle auffält. Ein Fehler
bei falschem Typ kommt dann erst später irgendwo tief in einem
Funktionsaufruf. Und bei einem Tippfehler beim Variablennamen hat man
schnell mal stillschweigend eine neue Variable angelegt, statt die schon
existierende zu überschreiben. Das kann einen bei der Fehlersuche auch
in den Wahnsinn treiben.
Präfixe für Typen finde ich meist überflüssig. Wichtig ist mir
allerdings, schon im Namen zwischen lokalen und globalen Variablen zu
unterscheiden.
Lokale Variablen fangen bei mir mit Kleinbuchstaben an, globale mit
Großbuchstaben. Dasselbe bei Funktionsnamen. Funktionen, die nur mit
lokalen Variablen arbeiten, fangen klein an. Funktionen, die auf globale
Variablen zugreifen, bekommen einen Namen, der mit Großbuchstaben
anfängt. Ausnahme ist nur 'main', da er von außen vorgegeben ist.
Die Länge der Variablen hängt davon ab, wie speziell die Aufgabe der
Variablen ist, globale Variablen sind da naturgemäß länger.
Ich benutze auch einfache Buchstaben als lokale Variablen, die aber
immer dieselben Aufgaben und denselben Typ haben, egal in welcher
Funktion. Meist sind es diejenigen, die Kernighan&Ritchie schon in ihren
Beispielfunktionen verwendet haben.
So ist 'i' immer die Indexvariable für einfache for-Schleifen und int.
Stringanalyse wird mit 's' gemacht, ein Lesezeiger (const char *).
Brauche ich mehrere Variablen dieser Art, fangen sie ebenfalls mit 's'
an, also s1,s2 ... oder zB sr für Reststring. Das Schreiben von Strings
geschieht entsprechend mit 't' (für target) als Schreibzeiger (char *).
Jobst Q. schrieb:> globale mit> Großbuchstaben.Jobst Q. schrieb:> Funktionen, die auf globale> Variablen zugreifen, bekommen einen Namen, der mit Großbuchstaben> anfängt.
Und indem man globale Variablen ganz vermeidet spart man sich auch diese
Komplexität.
Dr. Sommer schrieb:> Und indem man globale Variablen ganz vermeidet spart man sich auch diese> Komplexität.
können Interrupt-Routinen dann überhaupt noch etwas sinnvolles tun?
uC-Bastler schrieb:> können Interrupt-Routinen dann überhaupt noch etwas sinnvolles tun?
ISRs sind eine Ausnahme... Man baut sich 1 globale Variable mit den
relevanten Daten, auf die in der ISR 1x und ggf. in der main() 1x
zugegriffen wird. Einen Zeiger/Referenz darauf übergibt man an alle
Funktionen die es brauchen. So wird die globale Variable zentral genutzt
und für diese 2 Funktionen braucht man dann auch keine spezielle
Namenskonvention.
Rolf M. schrieb:> In Python definiert man Variablen nicht. Man weist einfach was zu, und> wenn sie noch nicht existiert, wird sie dann erzeugt
Ja, sorry, habe ich auch so gemeint...Katzenklappe = 3...
Gruß Rainer
Rolf M. schrieb:> In Python definiert man Variablen nicht. Man weist einfach was zu, und> wenn sie noch nicht existiert, wird sie dann erzeugt. Und sie bekommt> dann einfach den Typ, den die rechte Seite der Zuweisung hatte. Und bei> der nächsten Zuweisung wieder. Nachteil ist, dass die Variable munter> ihren Typ wechseln kann, ohne dass das an der Stelle auffält. Ein Fehler> bei falschem Typ kommt dann erst später irgendwo tief in einem> Funktionsaufruf. Und bei einem Tippfehler beim Variablennamen hat man> schnell mal stillschweigend eine neue Variable angelegt, statt die schon> existierende zu überschreiben. Das kann einen bei der Fehlersuche auch> in den Wahnsinn treiben.
Ach naja, so einen Fehler kann man sich in C++ mit dem Shadowing auch
leicht bauen ...
Sven B. schrieb:> Rolf M. schrieb:
...
Ja, aber...und wenn es hier vielleicht nicht hingehört...du arbeitest
fast immer mit Klassen, deren Methoden und Funktionen im Modul definiert
sind. Damit ist schon eine große Eindeutigkeit gegeben. Weiß nicht, ob
das in C genau so ist, aber in einer OO-orientierten Sprache sollte das
relativ eindeutig u n d lesbar sein oder?
Gruß Rainer
Sven B. schrieb:> Ach naja, so einen Fehler kann man sich in C++ mit dem Shadowing auch> leicht bauen ...
Man muß aber die dann folgende Compiler-Warnung nicht ignorieren.
A. S. schrieb:> Popcorn
"Popcorn" bietet sich als Name für ein mehrdimensionales Feld an. Ist
aber auf Grund der Kleinheit der einzelnen Elemente nur für Bits
geeignet. Für längere Strukturen bietet sich "Rohr" oder "Kastenprofil"
als Bezeichnung an.
"Sabbel" dann als Bezeichnung für einen String mit > 100 Zeichen.
Dr. Sommer schrieb:> Und indem man globale Variablen ganz vermeidet spart man sich auch diese> Komplexität.
Und schafft sich durch die Vermeidung neue Komplexitäten. Mir sind
globale Variablen lieber als lange Parameterlisten, in denen dann oft
immer wieder dasselbe steht. Da finde ich globale, also
funktionsübergreifende Variablen für das, was man immer wieder braucht,
deutlich praktischer. Je kürzer die Parameterlisten, um so weniger muss
man auf die Reihenfolge achten.
Manche Daten braucht man dauerhaft. Da finde ich es weder sinnvoll, die
alle in main als lokale Variablen zu deklarieren, noch sie mit static
auf die Funktionen zu verteilen.
Jobst Q. schrieb:> Mir sind> globale Variablen lieber als lange Parameterlisten, in denen dann oft> immer wieder dasselbe steht.
Daher kapselt man zusammen gehörende Daten in Klassen. Die meisten
Funktionen kommen dann mit 1-3 Parametern aus, aus denen sich die
Funktion dann die entsprechenden Daten holt.
In Java funktioniert es doch auch - da gibt es überhaupt keine
globalen Variablen.
Dr. Sommer schrieb:> Daher kapselt man zusammen gehörende Daten in Klassen.
Aber innerhalb einer Klasse sind die meisten Variablen eben nicht lokal.
Bei einer Quelldatei pro Klasse sind die Membervariablen im gesamten
Quelltext verfügbar und damit global.
Dr. Sommer schrieb:> In Java funktioniert es doch auch - da gibt es überhaupt keine globalen> Variablen.
Deshalb ist Java auch der Renner bei uC.
Oh, vertan: doch wohl eher bei Anwendungen ohne konkrete reale Objekte.
Niemand sollte die Sichtbarkeit höher wählen als nötig. Und Daten
sollten gekapselt und strukturiert sein. Soweit Zustimmung.
Aber ob ich ein globales struct mit 100 Elementen habe, einen globalen
Zeiger darauf oder eine globale Funktion die den Zeiger zurückgibt, ist
oft gleichwertig.
Jobst Q. schrieb:> Aber innerhalb einer Klasse sind die meisten Variablen eben nicht lokal.
Richtig.
Jobst Q. schrieb:> Bei einer Quelldatei pro Klasse sind die Membervariablen im gesamten> Quelltext verfügbar und damit global.
Nur in den Funktionen eben dieser Klasse. Sie sind eben nicht global.
Dass Member-Funktionen einer Klasse auf die Member-Variablen zugreifen
ist klar - sonst wären es keine Member-Funktionen - womit sich die
Konvention mit der Großschreibung dann erledigt.
Eine Konvention die ggf. noch sinnvoll sein kann ist "i" für Index und
"n" für Number (Anzahl). Ein Code kann dann so aussehen:
Man muss halt nur wissen dass "i" hier nicht für Integer steht.
A. S. schrieb:> Aber ob ich ein globales struct mit 100 Elementen habe, einen globalen> Zeiger darauf oder eine globale Funktion die den Zeiger zurückgibt, ist> oft gleichwertig.
Deswegen macht man das eben nicht global. Bei vernünftiger
objektorientierter Programmierung übergibt man jeder Funktion was sie
gerade braucht, inklusive dem impliziten this-Pointer. So wird der Code
übersichtlich und man spart sich undurchsichtige Verpflechtungen über
globale Variablen. Das ist auch auf eingebetteten Systemen sehr gut
machbar - habe ich schon oft.
A. S. schrieb:> Deshalb ist Java auch der Renner bei uC.
Man kann sich die guten Dinge da abschauen. Und ja, es gibt Java für uC.
Jobst Q. schrieb:> Aber innerhalb einer Klasse sind die meisten Variablen> eben nicht lokal. Bei einer Quelldatei pro Klasse sind> die Membervariablen im gesamten Quelltext verfügbar> und damit global.
Kuriose Sprachlogik.
Alles, was nicht auf Deinen Garten beschränkt ist, ist
global?
Ich würde eher verschiedene Grade von Lokalität unterscheiden
(blocklokal, funktionslokal, modullokal,...).
Dr. Sommer schrieb:> Jobst Q. schrieb:>> Bei einer Quelldatei pro Klasse sind die Membervariablen im gesamten>> Quelltext verfügbar und damit global.>> Nur in den Funktionen eben dieser Klasse. Sie sind eben nicht global.> Dass Member-Funktionen einer Klasse auf die Member-Variablen zugreifen> ist klar - sonst wären es keine Member-Funktionen - womit sich die> Konvention mit der Großschreibung dann erledigt.
Es geht mir um die wesentliche Unterscheidung zwischen lokalen und
nicht-lokalen Variablen. Die nicht-lokalen Variablen fangen bei mir mit
Großbuchstaben an. Wenn dich daran die Bezeichnung global stört, ersetz
es einfach durch nicht-lokal.
Jobst Q. schrieb:> Es geht mir um die wesentliche Unterscheidung zwischen lokalen und> nicht-lokalen Variablen.
Diese Unterscheidung macht doch nur Sinn in einer Nicht-OO-Umgebung!
Wenn du z.B. die Parameter eines Fensters in eine Klassendefinition
packst, dann kannst du überall mit Class.Param drauf zugreifen und in
der Klasse hast du möglicherweise den Typ expliziert definiert...das ist
aber alles andere, als in einem "normalen" Progrämmchen Variablen als
global zu definieren!
Gruß Rainer
Joern DK7JB .. schrieb:> Wie benennt ihr eure Variablen eindeutig in der Programmiersprache C> damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine> bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Benutzt Ihr keine IDE? Meine Bezeichner sind unterschiedlich bunt, und
wenn ich darüber "hover", bekomme ich den Typ auch angezeigt ...
Wilhelm M. schrieb:> Benutzt Ihr keine IDE? Meine Bezeichner sind unterschiedlich bunt, und> wenn ich darüber "hover", bekomme ich den Typ auch angezeigt ...
Eben, deswegen ist das Thema weniger wichtig, als der Geschmack der
Tomaten, die ich gleich essen werde.
Hauptsache es herrscht bei allen beteiligten mindestens projektweit
Konsistenz. Besonders leserlich finde ich es aber nicht, wenn man die
Namen mit Prä- und Suffixen zumüllt.
Ich denke, da überwiegen die Nachteile eindeutig die Vorteile, zumal
(fast) jede Popel-IDE den Typ anzeigen kann.
A. S. schrieb:> Deshalb ist Java auch der Renner bei uC.>> Oh, vertan
Mag dir nicht klar sein, aber Java laeuft auf SIM-Karten und anderen
Smart-Cards.
Wilhelm M. schrieb:> Leute, diese ganze Diskussion stammt doch aus einer Zeit, als man> noch mit Zeileneditoren wie ed arbeitete.
Oder Arduino IDE. Die war damals um 2020 noch sehr aktuell und weit
verbreitet.
Stefanus F. schrieb:> Wilhelm M. schrieb:>> Leute, diese ganze Diskussion stammt doch aus einer Zeit, als man>> noch mit Zeileneditoren wie ed arbeitete.>> Oder Arduino IDE. Die war damals um 2020 noch sehr aktuell und weit> verbreitet.
Was war nochmal Arduino?
>>> Leute, diese ganze Diskussion stammt doch aus einer Zeit, als man>>> noch mit Zeileneditoren wie ed arbeitete.>> Oder Arduino IDE. Die war damals um 2020 noch sehr aktuell und weit>> verbreitet.Wilhelm M. schrieb:> Was war nochmal Arduino?
Diese komische altmodische Entwicklungsumgebung ohne Debugger.
Give me Five!
Stefanus F. schrieb:>>>> Leute, diese ganze Diskussion stammt doch aus einer Zeit, als man>>>> noch mit Zeileneditoren wie ed arbeitete.>>>> Oder Arduino IDE. Die war damals um 2020 noch sehr aktuell und weit>>> verbreitet.>> Wilhelm M. schrieb:>> Was war nochmal Arduino?>> Diese komische altmodische Entwicklungsumgebung ohne Debugger.> Give me Five!
Ich bin enttäuscht: wir beweisen doch die Korrektheit ;-)
Der Typ ist nur selten für das Verständnis wichtig. Ich hab schon genug
damit zu tun, kurze und die Funktion beschreibende Namen auszudenken, da
muß ich nicht noch die Lesbarkeit durch unnütze Präfixe und Suffixe
erschweren.
Eine der erfolgreichsten Software Firmen ist Microsoft. Eine der
Ursachen ist, sie beginnen jede Variable mit einem Typvorsatz und die
Teile der Namen beginnen mit einem Großbuchstaben. Es gibt Profis und
Stümper. Man sollte von den Profis lernen.
Profi schrieb:> Eine der erfolgreichsten Software Firmen ist Microsoft. Eine der> Ursachen ist, sie beginnen jede Variable mit einem Typvorsatz und die> Teile der Namen beginnen mit einem Großbuchstaben. Es gibt Profis und> Stümper. Man sollte von den Profis lernen.
Wie schon in diesem Thread erwähnt wurde, hat selbst Microsoft
eingesehen, dass das Unsinn war.
Yalu X. schrieb:> Ganz abgesehen davon entspricht die Microsoftsche Ungarische Notation> nicht den ursprünglichen Ideen ihres Erfinders Simonyi. Zudem hat auch> Microsoft längst den Unsinn darin erkannt und verbietet mittlerweile (in> .NET-Bibliotheken) sogar ihre Nutzung.
Profi schrieb:> Eine der erfolgreichsten Software Firmen ist Microsoft. Eine der> Ursachen ist, sie beginnen jede Variable mit einem Typvorsatz und die> Teile der Namen beginnen mit einem Großbuchstaben. Es gibt Profis und> Stümper. Man sollte von den Profis lernen.
Laut Wikipedia: https://de.wikipedia.org/wiki/Ungarische_Notation
sollte eigentlich der Verwendungszweck angegeben werden. Die Notierung
des Datentyps ist
> für den schlechten Ruf der Konvention verantwortlich, weil die Benennung einer
Variablen nach dem Datentyp wenig zum Verständnis des Inhalts beiträgt und
trotzdem viel Aufwand verursacht.
Typo-Konventionen (z.B. CamelCase oder _) oder ein Präfix n für Anzahl,
i für Index oder auch p für Pointer sind doch ok. Schlimm sind "pac" für
pointer auf Array of char oder "i" bzw. "i32" für Integer.
Egon D. schrieb:> Alles, was nicht auf Deinen Garten beschränkt ist, ist> global?>> Ich würde eher verschiedene Grade von Lokalität unterscheiden> (blocklokal, funktionslokal, modullokal,...).
Dann sagt lokal garnichts mehr aus. Blocklokal ist zwar möglich, aber
nicht sinnvoll. Modullokal ist eben nicht mehr lokal, man könnte
modulregional sagen, wenn man das Wort global nicht mag.
Solange ein Programm nur aus einem Modul bzw einem Quelltext besteht,
ist global und modulregional identisch. Erweitert man nun das Programm
um ein Modul, sind alle bisher globalen Variablen nicht mehr global im
Sinne von programmweit gültig, obwohl sich nichts an ihnen geändert hat.
Global wären dann nur noch Variablen, die als extern deklariert sind.
Der Unterschied zwischen modulweit und programmweit ist also eher
theoretischer Natur. Dagegen ist der Unterschied zu (funktions-)lokalen
Variablen drastisch und von großer praktischer Bedeutung.
Lokale Variablen sind im allgemeinen auch temporär, also zeitlich nur
gültig solange sie abgearbeitet wird. Es gibt zwar auch die Möglichkeit
statische Variablen in einer Funktion zu deklarieren, das schafft aber
meist mehr Probleme als sie löst.
Jobst Q. schrieb:>> Ich würde eher verschiedene Grade von Lokalität unterscheiden>> (blocklokal, funktionslokal, modullokal,...).>> Dann sagt lokal garnichts mehr aus. Blocklokal ist zwar möglich, aber> nicht sinnvoll. Modullokal ist eben nicht mehr lokal, man könnte> modulregional sagen, wenn man das Wort global nicht mag.
Deine Definition von "lokal" beschränkt sich auf eine Weltsicht von "es
gibt Funktionen und die haben ein drinnen (lokal) und ein draußen
(global)". Das ist manchmal sinnvoll und manchmal nicht. Vor allem
schränkt es dich in deiner Denkweise stark ein.
Wenn ich ein Buch verleihe, dann mache ich es jemandem zugänglich, der
außerhalb meines Scopes liegt (ergo: nicht lokal). Aber deswegen mache
ich es noch lange nicht jedem Menschen auf dieser Welt zugänglich (ergo:
nicht global).
Im Übrigen nutze ich blocklokale Variablen sehr gerne (z.B. in
Schleifen).
Jobst Q. schrieb:> Solange ein Programm nur aus einem Modul bzw einem Quelltext besteht,> ist global und modulregional identisch. Erweitert man nun das Programm> um ein Modul, sind alle bisher globalen Variablen nicht mehr global im> Sinne von programmweit gültig, obwohl sich nichts an ihnen geändert hat.> Global wären dann nur noch Variablen, die als extern deklariert sind.
Eine etwas merkwürdige Logik. Wenn man ihr weiter folgt, wären alle
lokalen Variablen auch global, solange man nur eine Funktion (also
main()) hat, da man sie ja dann auch vom ganzen Programm aus sieht und
sie auch über die gesamte Programmlaufzeit existieren.
Rolf M. schrieb:> solange man nur eine Funktion (also> main()) hat, da man sie ja dann auch vom ganzen Programm aus sieht und> sie auch über die gesamte Programmlaufzeit existieren.
Wenn Du so willst, ja. Bzw. Nein. Auch dann würdest Du ja (nach der
Initialisierung) eine Endlosschleife haben. Und die wiederum hat viele
Blöcke, von denen aus gesehen es lokale (nur innerhalb dieses Blocks)
und globale (oberhalb dieses Blocks) Variablen gibt.
Wenn auch Spaghtetti-Code, das Prinzip ist gleich (nur, dass die Blöcke
im Gegensatz zu Funktionen keine Parameter)
Von daher finde ich die Unterscheidung Stimmig, egal ob Block, File oder
Projekt:
Globale Variablen (von außerhalb)
Parameter (Übergeben)
lokale Varialen (nur innerhalb)
A. S. schrieb:> Und die wiederum hat viele Blöcke, von denen aus> gesehen es lokale (nur innerhalb dieses Blocks)> und globale (oberhalb dieses Blocks) Variablen gibt.
Membervariablen sind aus mehreren Blöcken (nämlich den Methoden)
erreichbar, gleichzeitig aber nur von dort.
Wie würdest du sie einordnen? Lokal, global oder doch keins davon?
Profi schrieb:> sie beginnen jede Variable mit einem Typvorsatz und die> Teile der Namen beginnen mit einem Großbuchstaben. Es gibt Profis und> Stümper. Man sollte von den Profis lernen.
Man kann aber auch den Linux Kernel anschauen Beispiel:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/audit.c
Das ist auch ein großes Projekt und ziemlich erfolgreich. Klar. Das ist
kein riesen SW-Unternehmen. Trotzdem ist es Code von hoher Qualität,
obwohl der Coding-Style so ziemlich das Gegenteil ist.
Das wichtigste meiner Meinung nach ist, dass es sich flüssig liest. Und
das ist, finde ich, bei ungarischer Notation nicht der Fall. Auch die
Einrückung des Codes um einen TAB (entspricht 8 Leerzeichen) hilft, dass
der Code sehr lesbar ist, obwohl vermutlich die meisten mit dem Kopf
darüber schütteln
Rolf M. schrieb:> Jobst Q. schrieb:>>> Solange ein Programm nur aus einem Modul bzw einem Quelltext besteht,>> ist global und modulregional identisch. Erweitert man nun das Programm>> um ein Modul, sind alle bisher globalen Variablen nicht mehr global im>> Sinne von programmweit gültig, obwohl sich nichts an ihnen geändert hat.>> Global wären dann nur noch Variablen, die als extern deklariert sind.>> Eine etwas merkwürdige Logik. Wenn man ihr weiter folgt, wären alle> lokalen Variablen auch global, solange man nur eine Funktion (also> main()) hat, da man sie ja dann auch vom ganzen Programm aus sieht und> sie auch über die gesamte Programmlaufzeit existieren.
Das ist nicht meine Logik, deshalb "im Sinne von programmweit gültig".
Von manchen wird global so verstanden, ich habe es eher als nicht-lokal
verstanden und so ist auch die Unterscheidung in meiner
Benennungskonvention: Nur lokale (temporäre) Variablen beginnen mit
Kleinbuchstaben.
S. R. schrieb:> Membervariablen sind aus mehreren Blöcken (nämlich den Methoden)> erreichbar, gleichzeitig aber nur von dort.>> Wie würdest du sie einordnen? Lokal, global oder doch keins davon?
Könnte man regional nennen.
M. H. schrieb:> Das ist auch ein großes Projekt und ziemlich erfolgreich. Klar. Das ist> kein riesen SW-Unternehmen. Trotzdem ist es Code von hoher Qualität,
Nein, er ist nur von durchgängig ziemlich gleicher, aber nicht von
wirklich hoher Qualität.
Um das ganz klar zu sagen: Auch dieser Zustand ist ein Zustand, der den
Linux-Kernel ganz klar über die meiste kommerzielle Software erhebt.
Aber leider: immer noch weit entfernt von Perfektion.
Man braucht einfach mal nur die Kernel-Updates zu verfolgen, um einen
Eindruck davon zu bekommen, wo die Säge klemmt. Das sind immer und immer
wieder Sachen, die mit einer richtigen Hochsprache einfach garnicht erst
passieren könnten. Sprich: hier ist schlicht die (wegen der Effizienz
gewollte) Maschinennähe und deren gleichzeitig unzureichende
Unterstützung durch die gewählte Programmiersprache "Schuld" an den
Sicherheitslücken. Im Endeffekt ist es aber natürlich die Unfähigkeit
der reinen Hochsprachenprogrammierer, die potentiellen Sicherheitslücken
auch ohne Compilerhilfe (bzw. die Hilfe eines Laufzeitsystems)
vorausschauend erkennen und verhindern zu können.
> obwohl der Coding-Style so ziemlich das Gegenteil ist.
Assemblernah, soweit es C halt zuläßt. Absolut sinnvoll im Sinne der
Aufgabe. Das Ziel des aus der Sicht der C-only-Wichser "schlechten"
Codierstils ist ganz klar: Wir machen es dem Compiler so einfach wie
möglich, effizienten Code zu erzeugen. Weil wir (im Gegensatz zu diesen
unsäglichen C-Only-Wichsern) wissen, dass Compiler halt nach wie vor
weit weg davon sind, perfekt zu sein.
c-hater schrieb:> C-only-Wichser
Ja, gute Programmierer können auch noch mehr Sprachen wie Python, Scala,
Scheme, Mathematica, SQL, Haskell, Erlang, JavaScript, Java, ... und
können von dort Paradigmen übernehmen.
Dr. Sommer schrieb:> c-hater schrieb:>> C-only-Wichser>> Ja, gute Programmierer können auch noch mehr Sprachen wie Python, Scala,> Scheme, Mathematica, SQL, Haskell, Erlang, JavaScript, Java, ... und> können von dort Paradigmen übernehmen.
Und gute Programmieren können vor allem auch Assembler, oft von all
den Sache, mit denen sie im Läufe der Jahrzehnte Kontakt hatten. z80,
8048, 8051, x86, AVR, ARM jeweils privat, oder eben /370 beruflich, wenn
auch schon 2 Jahrzehnte nicht mehr.
Einfach nur die Mainstreamsprache zu hassen ist keine Leistung. Selbst
wenn man bei C die Freiheit hat sich Probleme einzufangen, Assembler ist
C darin haushoch überlegen.
Rufus Τ. F. schrieb:> Eine weitere Konvention aus ähnlichem Dunstkreis ist "CamelCase", bei> dem Variablennamen, die aus mehreren Wörtern zusammengesetzt werden, mit> Großbuchstaben im Wort geschrieben werden
Am übersichtlichsten.
Den Typ da noch reinzuquetschen ist vollkommen überflüssig.
Axel S. schrieb:> sein, der den Code lesen und pflegen muß. Der Typ ist dafür in 99.9% der> Fälle aber vollkommen irrelevant bzw. wenn erforderlich, von der IDE> mit nur einem Tastendruck abrufbar ("zeige die Definition des Symbols> unter der Maus").
Genau.
Und "Konstanten.hh" und "Variablen.hh" mit Blöcken für verschiedene
Routinen, wo Variablen und Konstanten zusammengelegt werden, machen
das Ganze übersichtlich genug.
Rufus Τ. F. schrieb:> Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit> "gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden> Variablennamen gab:>> a
...
> aaaaa
In kurzen Routinen mache ich mir nicht die Mühe, Variablen,
insbesondere die Loop- und Umrechnungsvariablen, anders als x,y,z,
zu benennen.
Marc V. schrieb:> In kurzen Routinen mache ich mir nicht die Mühe, Variablen,> insbesondere die Loop- und Umrechnungsvariablen, anders als x,y,z,> zu benennen.
Also zumindest bei geschachtelten Schleifen und mehrdimensionalen Arrays
verwende ich sprechende Laufvariablen da man selber oder der nächste sie
zu leicht verwechselt.
Blechbieger schrieb:> Also zumindest bei geschachtelten Schleifen und mehrdimensionalen Arrays> verwende ich sprechende Laufvariablen da man selber oder der nächste sie> zu leicht verwechselt.
'laufvariable' ist vielleicht geschwätziger, sagt aber auch nicht mehr
als 'i'. Und wenn es um verschachtelte Schleifen geht, sagt 'i1' 'i2'
usw auch ohne Buchstabenballast etwas über die Tiefe der Verschachtelung
aus.
Carl D. schrieb:> Selbst wenn man bei C die Freiheit hat sich Probleme einzufangen,> Assembler ist C darin haushoch überlegen.
Das ist signaturverdächtig. :-)
Blechbieger schrieb:> halte ich schon für übersichtlicher als x,y,z insbesondere wenn mit den> Variablen noch gerechnet werden soll.
Im 3D-Raster passt's doch.
Blechbieger schrieb:> Also zumindest bei geschachtelten Schleifen und mehrdimensionalen Arrays> verwende ich sprechende Laufvariablen da man selber oder der nächste sie> zu leicht verwechselt.
Kommt darauf an.
x,y,z können nur Loop- oder Umrechnungsechnungsvariablen sein.
Wenn man sich angewöhnt hat, die Variablen auch in dieser Reihenfolge
zu verwenden, gibt es keine Probleme, da immer Array[x][y][z].
Dabei ist für mich x immer die Breite, y die Höhe und z die Tiefe.
Das hat auch noch den Vorteil, dass man nicht raten muss, ob diese
Variablen noch für irgendetwas anderes benutzt werden.
Natürlich benutze ich auch sinnvolle Namen - da wo es nötig ist.
Ausführliche Kommentare (auch schon bei der Deklaration der
Variablen/Konstanten) finde ich jedoch viel nützlicher.
Man lernt so etwas spätestens dann zu schätzen, wenn nach ein paar
Monaten etwas im Programm geändert werden muss.
Rufus Τ. F. schrieb:> Ich bin mal einem von Betriebspraktikanten in jahrelanger Arbeit> "gepflegtem" Projekt begegnet, in dem es allen Ernstes die folgenden> Variablennamen gab:>> a
Wenn wir schon von Kollegen reden - schreibfaule Typen, die Zeilen
sparen wollen sind (für mich) viel schlimmer.
Wir hatten mal einen, der fast immer Dutzend oder mehr Variablen, die
zwar alle vom selben Typ waren, aber quer durch Programm in
verschiedenen Routinen benutzt wurden, in einer Zeile deklariert hat,
um Deklarationen so kurz wie möglich zu halten - prost mahlzeit.
C und C++ sind nicht stark typisiert, sodass die Verwendung von einer
Notation durchaus
nützlich sein kann. Vergleiche beispielsweise implizite casts unsigned
and signed
Typen unterschiedlicher Bitbreite in C und Go.
Am besten eine funktionale Sprache ohne Variablen verwenden ... F# oder
Haskell ;)
Ach, hier tummeln sich mal wieder die selbsternannten Pseudo-Gurus und
stellen ihre erweiterten Regeln für C gegenseitig vor.
Klasse!
Selbstverständlich reicht es nicht aus, sowas wie goto zu verteufeln,
nein, man muß auch alle gängigen Typen umbenennen und alle Zahlen außer
0 und 1 aus einem anständigen Programm entfernen und durch Bezeichner
ersetzen, die dann in 37 verschiedenen Fremd-Dateien verschiedener
Hersteller in die betreffende Zahl umgesetzt werden - und die
betreffenden Dateien gehören selbstverständlich NICHT zum Projekt.
Sowas treibt natürlich die schiere Anzahl von Bezeichnern in
astronomische Höhen, was offenbar gewollt ist. Merkt sich alles prima,
wenn man sonst nix im Kopf hat, gelle? Mit irgend etwas muß selbiger ja
gefüllt werden...
Hat mir dies doch neulich jemand angeraten. Das Schöne daran ist, daß er
mir versprach, sich nicht mehr mit mir unterhalten zu wollen, solange
ich seiner grandiosen Regel nicht nachkäme. Juchhei, endlich hält dieser
Kerl seine Klappe und nervt mich und den Rest der Welt nicht mehr mit
seinen Kommentaren. Ist ein erheblicher Gewinn für's Forum. Hoffentlich
hält er sich auch an sein Versprechen und ans Klappe-Halten.
Aber sowas ist selbstverständlich nur der Anfang. Man muß schließlich
auch Regeln für das Benennen von Typen, Variablen, Funktionen und
sonstwas aufstellen, wo kämen wir denn hin, wenn irgend jemald so
einfach nur den gesunden Menschenverstand walten ließe?
Also, um hier nen positiven Beitrag zu leisten, schlage ich vor, auch
ein Kürzel des Autors sowie ein weiteres Kürzel die Datei betreffend, wo
die Entität deklariert worden ist, in den Namen dieser Entität
aufzunehmen. Kurze und prägnante Namen kann ja jeder, das muß weg! So
richtig lange und aussagekräftige Namen müssen her, die man nur
entziffern kann, wenn man die dazu zu befolgenden Regeln sich ausdruckt
und an die Wand pinnt.
Sowas nennt man dann Fortschritt oder C 2019.
Ich habe mich übrigens neulich nicht getraut, den Verkäufer nach ner
tragbaren USB-Festplatte mit 4 Tera-Uint8Tees zu fragen. Aber vielleicht
kann das ja mal einer von euch probieren und davon berichten.
Also: Beckmesser war die Knalltüte in Wagners Meistersingern, der selber
zwar nicht wirklich singen konnte, dafür aber mit dem Buch der ehernen
Regeln unter'm Arm herum lief und allen Meistern ihre angeblichen
Regelverstöße vorhalten wollte. Eben so einer aus der Klasse der
selbsternannten Gurus. Aber er konnte deshalb trotzdem nicht gut singen.
Eine Backpfeife eben.
W.S.
Carl D. schrieb:> Und gute Programmieren können vor allem auch Assembler, oft von all> den Sache, mit denen sie im Läufe der Jahrzehnte Kontakt hatten.
Nicht jeder gute Programmierer hat vor mehreren Jahrzehnten angefangen,
die damaligen Systeme (mangels Alternativen) in Assembler zu
programmieren. Manche sind auch schlicht nicht alt genug.
Lieber Dr. Sommer, bitte unterlasse doch solche vor allem Anfänger
verwirrenden Aussagen:
1.) Dr. Sommer schrieb:> C++ hat überhaupt keine structs2.) Dr. Sommer schrieb:> M. H. schrieb:>> Na klar hat C++ structs:>> http://www.cplusplus.com/doc/tutorial/structures/>> cplusplus.com ist keine Referenz. Da steht viel Unsinn. C++ hat keine> Structs, nur Klassen. Das Schlüsselwort "struct" definiert eine> Klasse, in der per default alles "public" ist. Siehe z.B.:3.) Dr. Sommer schrieb:> Wenn aber "struct" eine Klasse definiert (siehe das Zitat), wie> definiert man dann structs?
Zu 1.)
Wenn C++ keine structs hätte, gäbe es in C++ das Schlüsselwort "struct"
nicht bzw. müsste bei Verwendung zu einer Fehlermeldung führen.
zu 2.)
Ob cplusplus.com nun EINE Referenz für C++ ist oder eben DEINE Referenz
für C++ gerade nicht ist, spielt keine Rolle. Tatsache ist, es gibt das
Schlüsselwort struct in C++, nur dessen Bedeutung ist halt anders als in
C, siehe
https://de.cppreference.com/w/cpp/keywordhttps://namespace-cpp.de/std/doku.php/kennen/keywords
"Klassen und Strukturen (struct) sind in C++ gleichwertig mit einer
Ausnahme: Das voreingestellte Zugriffsrecht einer Klasse ist private.
C, C++ : Das Schlüsselwort struct leitet die Deklaration bzw. Definition
eines Verbunddatentyps (Struktur) ein, der Daten unterschiedlicher Typen
bündelt. In C++ dürfen Strukturen, anders als in C, auch Methoden
enthalten. Damit sind Klassen (class) und Strukturen gleichwertig mit
einer Ausnahme: Das voreingestellte Zugriffsrecht einer Struktur ist
public."
zu 3.)
Brauchst du Beispiele dafür?
http://programmingexamples.wikidot.com/struct
Anfänger schrieb:> Wenn C++ keine structs hätte, gäbe es in C++ das Schlüsselwort "struct"> nicht bzw. müsste bei Verwendung zu einer Fehlermeldung führen.
Das ist doch nur eine Definitionsfrage.
C++ hat keine „reinen“ structs, das Schlüsselwort "struct" ist dort nur
ein alternatives Schlüsselwort für Klassen.
Aber das wurde nun schon zur Genüge hier durchgekaut.
Anfänger schrieb:> Zu 1.) Wenn C++ keine structs hätte, gäbe es in C++ das Schlüsselwort> "struct" nicht bzw. müsste bei Verwendung zu einer Fehlermeldung führen.
Es gibt hier 2 Ebenen. Die Syntax und die Semantik. Das ist auch etwas,
das Anfänger verstehen müssen. In der Syntax steht zwar "struct", aber
die Bedeutung ist "Klasse".
Anfänger schrieb:> Ob cplusplus.com nun EINE Referenz für C++ ist oder eben DEINE Referenz> für C++ gerade nicht ist, spielt keine Rolle.
Die einzige Referenz die zählt ist der C++ Standard. Den habe ich
zitiert. Und da gibt es keine Strukturen, nur Klassen, welche man über
die Schlüsselwörter "struct" oder "class" definieren kann.
Anfänger schrieb:> "Klassen und Strukturen (struct) sind in C++ gleichwertig mit einer> Ausnahme: Das voreingestellte Zugriffsrecht einer Klasse ist private.
Irgendwelche Websiten - noch dazu deutsche Übersetzungen - sind
irrelevant. Im Internet und sogenannten Online-Tutorials und auch in
Büchern wird unendlich viel Blödsinn über C++, aber auch über C,
verbreitet. Nur der Standard zählt. Das "struct" Keyword wird da sogar
oft in Beispielen verwendet - um Klassen zu definieren.
Anfänger schrieb:> Ob cplusplus.com nun EINE Referenz für C++ ist oder eben DEINE Referenz> für C++ gerade nicht ist, spielt keine Rolle. Tatsache ist, es gibt das> Schlüsselwort struct in C++, nur dessen Bedeutung ist halt anders als in> C, siehe>> https://de.cppreference.com/w/cpp/keyword> https://namespace-cpp.de/std/doku.php/kennen/keywords
Nunja, die einzige wirkliche Referenz für C++ ist die ISO-Spezifikation.
Dort heißt es in Kapitel 9 "Classes":
A structure is a class defined with the class-key struct; its members
and base classes (clause 10) are public by default
Rolf M. schrieb:>> A structure is a class defined with the class-key struct; its members> and base classes (clause 10) are public by default
was den Vorteil hat, kompatibel zu bestehendem C-Code zu sein.
Das, die Kompatibilität zur Vorgängern/Vorversionen ist der Grund für
jede C++ "Sprachungereimtheit". Das ist aber auch der Grund dafür, daß
sich C++ mit so vielen "besseren" Sprachen vergleichen lassen muß. Es
hat sie schlicht alle überlebt.
Carl D. schrieb:> Rolf M. schrieb:>>>> A structure is a class defined with the class-key struct; its members>> and base classes (clause 10) are public by default>> was den Vorteil hat, kompatibel zu bestehendem C-Code zu sein.
Ja, das Schlüsselwort struct existiert hauptsächlich aus Gründen der
Abwärtskompatibilität zu C und nicht etwa, um dem faulen Programmierer
das Tippen des Wörtchens "public" zu ersparen. Es wäre ja sonst ziemlich
unsinnig, für die beiden Dinge (class und struct), die sich lediglich in
der defaultmäßigen Sichtbarkeit ihrer Elemente unterscheiden, so völlig
unterschiedliche Bezeichnungen zu wählen.
Deswegen benutze ich struct ausschließlich C-like, d.h. für reine
Datenstrukturen ohne Elementfunktionen, und class ausschließlich für
echte Klassen, d.h. solche, die nicht nur Datenelemente, sondern auch
Elementfunktionen enthalten. Auch eine (selten vorkommende) echte
Klasse, in der sämtliche Elemente public sind, ist bei mir eine class,
auch wenn ich mit struct etwas weniger zu tippen hätte.
Das ganze ist natürlich eine eher philosophische bzw. linguistische
Frage, aber wenn man schon die freie Wahl hat, dürfen auch mal die
Geisteswissenschaften zu Wort kommen ;-)
Yalu X. schrieb:> Deswegen benutze ich struct ausschließlich C-like, d.h. für reine> Datenstrukturen ohne Elementfunktionen, und class ausschließlich für> echte Klassen, d.h. solche, die nicht nur Datenelemente, sondern auch> Elementfunktionen enthalten. Auch eine (selten vorkommende) echte> Klasse, in der sämtliche Elemente public sind, ist bei mir eine class,> auch wenn ich mit struct etwas weniger zu tippen hätte.
Den besten Vorschlag den ich zu dieser Unterscheidung gehört habe, war
"class" für Dinge zu verwenden, die eine Invariante haben. Wenn jeder
beliebige Wert für jedes der Member ok ist, ist "struct" meist sinnvoll.
Das passt auch ziemlich gut zu dem, was man so intuitiv tun würde. Es
passt auch gut zu dem "alles ist public"-Konzept.
W.S. schrieb:> nein, man muß auch alle gängigen Typen umbenennen und alle Zahlen außer> 0 und 1 aus einem anständigen Programm entfernen und durch Bezeichner> ersetzen, die dann in 37 verschiedenen Fremd-Dateien verschiedener> Hersteller in die betreffende Zahl umgesetzt werden - und
Es ist bestens bekannt, daß Du Fan von "magic numbers" im Quelltext
bist, denn die lassen sich ja viel einfacher im Datenblatt finden.
Rufus Τ. F. schrieb:> Es ist bestens bekannt..
Ach, du nörgelst mal wieder.
Aber ich kann dich trösten: Das zuständige Hardware-Register, wo die
Zahl reinkommt, findet man im RefManual ganz leicht. Und dann sieht man
auch im zugehörigen Text sowohl die Stelle, wo die Zahl hinkommt, als
auch..
_TADAA!_
eine zumeist relativ ausführliche Beschreibung, was verschiedene Werte
für diese Zahl tatsächlich bewirken. Aus dem schieren Namen geht das
nämlich selten bis nie hervor.
Das ist der wahre Sinn von Refrenz-Manuals - und von den dort
nachlesbaren Zahlenwerten.
Ansonsten seid ihr ja noch immer beim Vergleichen eurer allerbesten
Einschränkungen für Variablen-Bezeichner.
Aber daß ihr jetzt beim Käuen von C++ und Klassen versus Structs
angekommen seid, ist ein Abdriften vom eigentlichen Thema.
Reißt euch zusammen und kreiert endlich die ultimative Vorschrift zum
Bilden eines qualifizierten Variablennamens. Die Welt wartet sehnsüchtig
drauf!
Ach ja, anbei fällt mir ein, daß man ja dann auch an die Chip-Hersteller
herantreten müßte - wo unser wackerer Rufus das Thema schon
angeschnitten hat. Die Bezeichner für Bitgruppen in den
Hardwareregistern entsprechen ja selten bis nie den noch festzulegenden
Variablennamen. Das muß natürlich sofort geändert werden - und dafür
sind dann die Chiphersteller heranzuziehen.
W.S.
W.S. schrieb:> Das zuständige Hardware-Register, wo die Zahl reinkommt, findet man im> RefManual ganz leicht.
Ärgerlicherweise wird das Hardwareregister dort aber mit einem Namen
angesprochen, statt dessen viel eindeutigere und verständlichere Adresse
zu verwenden. Denn letztlich ist doch genau das Deine
> ultimative Vorschrift zum Bilden eines qualifizierten Variablennamens.
Das hier ist doch viel verständlicher und eingängiger :
W.S. schrieb:> die dann in 37 verschiedenen Fremd-Dateien verschiedener> Hersteller in die betreffende Zahl umgesetzt werden - und die> betreffenden Dateien gehören selbstverständlich NICHT zum Projekt.> Sowas treibt natürlich die schiere Anzahl von Bezeichnern in> astronomische Höhen, was offenbar gewollt ist. Merkt sich alles prima,> wenn man sonst nix im Kopf hat, gelle? Mit irgend etwas muß selbiger ja> gefüllt werden...> Aber sowas ist selbstverständlich nur der Anfang. Man muß schließlich> auch Regeln für das Benennen von Typen, Variablen, Funktionen und> sonstwas aufstellen, wo kämen wir denn hin, wenn irgend jemald so> einfach nur den gesunden Menschenverstand walten ließe?> Also, um hier nen positiven Beitrag zu leisten, schlage ich vor, auch> ein Kürzel des Autors sowie ein weiteres Kürzel die Datei betreffend, wo> die Entität deklariert worden ist, in den Namen dieser Entität> aufzunehmen. Kurze und prägnante Namen kann ja jeder, das muß weg! So> richtig lange und aussagekräftige Namen müssen her, die man nur> entziffern kann, wenn man die dazu zu befolgenden Regeln sich ausdruckt> und an die Wand pinnt.
Du sprichst mir bei dem Post in allen Punkten aus der Seele.
Nur bei den NamensRegeln möchte ich unterscheiden:
a) Regeln, die sich jemand ausdenkt, und an die sich dann alle halten
sollen.
--> Das führt bei uns regelmäßíg ins Chaos. Das ist so, als würde man
ein Schrauben-Lager einrichten wollen, ohne zu wissen welche
Typen/Größen und in welchen Mengen.
b) Regeln, die evolutionär aus gewachsenem Code entstehen.
--> Hier gibt es häufig mehrere Strömungen, bestimmte Token-Typen zu
benennen. Nach einiger Zeit überwiegt eine Art und die anderen treten
bei Neubenennungen in den Hintergrund. Nach weiterer Zeit werden diese
als unnatürlich empfunden, aus der Hauptströumg eine Regel formuliert
und die anderen refakturiert.
W.S. schrieb:> Reißt euch zusammen und kreiert endlich die ultimative Vorschrift zum> Bilden eines qualifizierten Variablennamens. Die Welt wartet sehnsüchtig> drauf!
Niemand zwingt dich dazu, deine Variablen so zu benennen - bleib
doch einfach bei: a, ab, abc etc. wenn dich das glücklich macht.
Zusätzlich zu den sinnvollen Variablennamen setze ich bei Konstanten
immer ein c_ davor, etwa so:
1
#define c_SOF 0xAA
2
#define c_EOF 0xA9
3
4
// Position in Buffer
5
#define c_RcvAdr 0x01
6
#define c_SndAdr 0x02
7
#define c_CmdTyp 0x03
8
#define c_CmdLen 0x04
9
#define c_DatBlk 0x05
10
11
#define c_DatBlkLen 0x3F // 63 Byt max
So weiss ich immer womit ich es zu tun habe und kann die
Variablen ohne Probleme so deklarieren:
1
typedefstruct{
2
uint8_tMsg_SOF;
3
uint8_tRcvAdr;
4
uint8_tSndAdr;
5
uint8_tCmdTyp;
6
uint8_tCmdLen;
7
uint8_tDatBlk[c_DatBlkLen];
8
}USART_RAM;
9
USART_RAMUartRam;// CRC/ChkSum und EOF werden danach gesendet
Und wenn du es irgendwann einmal zu einem sinnvollem Programm,
welches länger als 5 Zeilen eigenes Code ist, schaffen solltest,
wirst du es wahrscheinlich selber so machen.
Natürlich, bei Copy&Paste braucht man sich keine Gedanken darüber
zu machen - Autor hat es wahrscheinlich schon getan - also bleib
ruhig bei kopieren.
W.S. schrieb:> Selbstverständlich reicht es nicht aus, sowas wie goto zu verteufeln,> nein, man muß auch alle gängigen Typen umbenennen und alle Zahlen außer> 0 und 1 aus einem anständigen Programm entfernen und durch Bezeichner> ersetzen
Du brauchst doch nur eine Rechtfertigung dafür, dass du in deinen
Projekten aus Faulheit nicht jedes Bit einzeln mit Namen definierst,
weil du ja auch die Hersteller-Header verteufelst... Dieses
Tretminenfeld aus Makros ist zwar nicht schön, aber immer noch besser
als Massen an Magic Numbers.
W.S. schrieb:> Also: Beckmesser war die Knalltüte in Wagners Meistersingern
Kennst du eigentlich nur diese eine Oper? Bist du daher einer von diesen
Intellektuellen?
Marc V. schrieb:> Ausführliche Kommentare (auch schon bei der Deklaration der> Variablen/Konstanten) finde ich jedoch viel nützlicher.
Grundsätzlich ein falscher Ansatz, aber ... nicht immer.
Jedesmal wenn es einen juckt einen Kommentar zu formulieren sollte man
zuvor überlegen, ob nicht der gleiche Informationsgewinn durch
Umbenennen des Bezeichners möglich ist. Zieht man das durch, bleibt
erstaunlich wenig übrig, das eines Kommentars bedarf und der Code wird
viel leichter verständlich.
doof:
Marc V. schrieb:> Zusätzlich zu den sinnvollen Variablennamen setze ich bei Konstanten> immer ein c_ davor, etwa so:#define c_SOF 0xAA> #define c_EOF 0xA9>> // Position in Buffer> #define c_RcvAdr 0x01> #define c_SndAdr 0x02> #define c_CmdTyp 0x03> #define c_CmdLen 0x04> #define c_DatBlk 0x05>> #define c_DatBlkLen 0x3F // 63 Byt max>> So weiss ich immer womit ich es zu tun habe und kann die> Variablen ohne Probleme so deklarieren:typedef struct {> uint8_t Msg_SOF;> uint8_t RcvAdr;> uint8_t SndAdr;> uint8_t CmdTyp;> uint8_t CmdLen;> uint8_t DatBlk[c_DatBlkLen];> } USART_RAM;> USART_RAM UartRam; // CRC/ChkSum und EOF werden danach gesendet
Und warum nicht direkt Strukturen verwenden?
> Und wenn du es irgendwann einmal zu einem sinnvollem Programm,> welches länger als 5 Zeilen eigenes Code ist, schaffen solltest,> wirst du es wahrscheinlich selber so machen.
Dein Codefragment sieht aber genau so aus, als gäbe es nur einen sehr
kleinen Kontext. Der einzige gemeinsame Nenner der 6 Konstanten (warum
auch immer die bei 1 anfangen) ist das c_. Und genau das verwendest Du
doch Deinen Worten nach auch woanders.
> Natürlich, bei Copy&Paste braucht man sich keine Gedanken darüber> zu machen - Autor hat es wahrscheinlich schon getan - also bleib> ruhig bei kopieren.
Hat das noch einen Bezug zu irgendwelchen Aussagen von W.S. hier?
Marc V. schrieb:> setze ich bei Konstanten> immer ein c_ davor, etwa so:> #define c_SOF 0xAA
Die allgemein übliche Konvention für Macros ist es, deren Namen in
Versalien zu schreiben. Deine "Konstanten" sind nämlich keine, sondern
Macros.
Wenn das eine Konstante sein soll, muss es so aussehen:
1
constuint8_tc_SOF=0xAA;
A. S. schrieb:> Und warum nicht direkt Strukturen verwenden?
Macht er doch, die Konstante (genauer: das #define) taucht als Anzahl in
dem Array aus Strukturen auf, das er anlegt.
Rufus Τ. F. schrieb:> A. S. schrieb:>> Und warum nicht direkt Strukturen verwenden?>> Macht er doch, die Konstante (genauer: das #define) taucht als Anzahl in> dem Array aus Strukturen auf, das er anlegt.
wofür c_RcvAdr, wenn es nur offsetof RcvAdr ist? In den meisten fällen
schreibt man doch eh X.RcvAdr. Und wenn man den Index braucht ...
doppelt gemoppelt failed schneller.
(nein, ein Array aus Strukturen ist das gar nicht, da hab' ich mich
offensichtlich vertan)
Wozu die anderen "Konstanten" gut sein sollen, hatte ich mir gar nicht
angesehen.
Ich versteh gar nicht, warum hier so viel auf C++, class und struct
rumgekaut wird, darum ging es dem OP doch gar nicht.
"Variablen eindeutig benennen damit der Typ eindeutig ist" - eigentlich
kann man sich die Frage selbst beantworten, indem man mal den Quellcode
von einigen Open Source-Projekten überfliegt, die soetwas nutzen und
sich daran orientieren: gängige Konvention ist wohl, dass dafür Präfixe
verwendet werden, wenn auch in unterschiedlichen Ausformungen. Ich
persönlich halte nicht viel davon. Letztlich kommt es, wie oft schon
angesprochen, auch darauf an, was für das jeweilige Projekt
vorgeschrieben ist. Für private Sachen kann man es dann halten, wie man
will.
Viel schlimmer als Variablen mit Präfixen zu versehen finde ich in C
eher die Unart von vielen Bibliotheken, für die primitiven Typen eigene
typdefs zu definieren. Statt mit etwas Einheitlichem wie uint32_t darf
man sich dann mit UINT, uint, UINT32, U32, u4 etc. herumschlagen. Hier
wäre es mir echt lieber, wenn nicht jeder das Rad neu erfinden bzw.
älterer Code in dieser Hinsicht mal gewartet werden würde.
Florian S. schrieb:> Viel schlimmer als Variablen mit Präfixen zu versehen finde ich in C> eher die Unart von vielen Bibliotheken, für die primitiven Typen eigene> typdefs zu definieren. Statt mit etwas Einheitlichem wie uint32_t
Ich glaube das hat historischen Grund. Die stdint.h gibt es erst seit
C99.
Stefanus F. schrieb:> Ich glaube das hat historischen Grund.
Ja, vor allem sind manche Betriebssystem-APIs auch ziemlich alt; das von
MS verwendete Namensschema (BYTE, WORD, DWORD etc.) ist bald 30 Jahre
alt (ich hab' zwar noch nie ein Windows 2.x-SDK gesehen, aber das werden
sie nicht für Windows 3.0 erst so erfunden haben, und das kam im Mai '90
raus).
Carl D. schrieb:> Einfach nur die Mainstreamsprache zu hassen ist keine Leistung.
Scheinbar irgendwie doch schon. Dem Hass liegt nämlich eine durch eigene
Arbeit mit Blut, Schweiss und Tränen gewonnene Erkenntnisse zugrunde, zu
der reine Lib-Zusammenleimer niemals gelangen werden...
> Selbst> wenn man bei C die Freiheit hat sich Probleme einzufangen, Assembler ist> C darin haushoch überlegen.
Das ist nach den Gesetzen der Informatik nicht wirklich so. Natürlich
ist unbestritten, dass man in Assembler sehr leicht Fehler produzieren
kann (Wer wüsste das besser als jemand wie ich, der sehr oft in
Assembler programmiert o;)
Aber: Der Unterschied zu C ist: Hier kann man nicht nur (fast) alle
typischen Fehler eines Assemblerprogrammierers begehen (denn die stehen
einem fast alle durch die mögliche Maschinennähe von C genauso frei zur
Verfügung), man kann DARÜBER HINAUS auch noch Unmassen C-Fehler begehen.
D.h.: Fehler in einer Abstraktionsschicht, die in Assembler schlicht
nicht passieren können, weil diese Abstraktionsschicht dort überhaupt
nicht existiert.
Schonmal von Komplexitätsbetrachtungen gehört? Das ist eine sehr schönes
Beispiel für eine nützliche Anwendung solcher Betrachtungen...
c-hater schrieb:> eigene Arbeit mit Blut, Schweiss und Tränen
Wenn Du doch nur einfach C programmieren gelernt hättest, wäre Dir viel
davon erspart geblieben.
c-hater schrieb:> Aber: Der Unterschied zu C ist: Hier kann man nicht nur (fast) alle> typischen Fehler eines Assemblerprogrammierers begehen (denn die stehen> einem fast alle durch die mögliche Maschinennähe von C genauso frei zur> Verfügung), man kann DARÜBER HINAUS auch noch Unmassen C-Fehler begehen.
Die Wahrscheinlichkeit, dass ich einen halbwegs komplexen Ausdruck wie
1
f = x + 2 * y * (z-1)
in Assembler falsch beschreibe, sind deutlich höher als in C.
Selbst dann noch, wenn man Überläufe usw. berücksichtigt.
Die Wahrscheinlichkeit, dass ich aus einem Array den falschen Wert lese,
weil ich mich bei der Indexberechnung verhakle, ist in Assembler
deutlich höher als in C.
Und ja, ich habe schon einiges mit Assembler gearbeitet (und auch
absichtlich). Es gibt Situationen, in denen will man Assembler. Das sind
aber äußerst wenige und selbst dort ist C-Interoperabilität hilfreich.
A. S. schrieb:> kleinen Kontext. Der einzige gemeinsame Nenner der 6 Konstanten (warum> auch immer die bei 1 anfangen) ist das c_.
Weil Offset 0 immer SOF ist.
Und wenn du den Rest nicht verstehst (bzw. keinen gemeinsamen Nenner
siehst), brauchen wir auch nicht weiter darüber zu diskutieren.
A. S. schrieb:> wofür c_RcvAdr, wenn es nur offsetof RcvAdr ist? In den meisten fällen> schreibt man doch eh X.RcvAdr. Und wenn man den Index braucht ...
Deswegen vielleicht:
1
union{
2
USART_RAMsRam;
3
uint8_tsbuff[5+c_DatBlkLen+3];
4
}Uart_un;
?
Ich bin mit solcher Bezeichnungsart bisher ganz gut gefahren,
habe auch nach mehreren Monaten keine Probleme zu verstehen, was
es bedeuten soll.
Thomas M. schrieb:> Jedesmal wenn es einen juckt einen Kommentar zu formulieren sollte man> zuvor überlegen, ob nicht der gleiche Informationsgewinn durch> Umbenennen des Bezeichners möglich ist. Zieht man das durch, bleibt> erstaunlich wenig übrig, das eines Kommentars bedarf und der Code wird> viel leichter verständlich.
Also, das stimmt bestimmt nicht, zumindest nicht für einigermassen
komplexe Programe.
Ich wollte schon unzählige Male beim ändern bzw. erweitern eines
Programs klüger sein als beim schreiben, ein paar Bytes/Takte einsparen
aber das hat sich ohne entsprechende Kommentare oft genug als ein
Schuss nach hinten erwiesen.
Wie gesagt, das alles mag Geschmacksache sein, nicht aber in einem
Team - da fliegt man ohne entsprechend kommentierten Code ganz
schnell raus.
Und bei Variablen wie a, aa, aaa... erst recht.
Rufus Τ. F. schrieb:> Wenn Du doch nur einfach C programmieren gelernt hättest,
So nicht, mein Lieber. Er hat C gelernt. Aber C gelernt zu haben und es
vernünftig benutzen zu können, ist etwa GANZ anderes, als diese
Programmiersprache zu mögen oder gar zu lieben (oder noch schlimmer: sie
zu verehren).
Nee, mit etwas Abstand betrachtet, ist C eine zwar versatile, aber
dennoch häßliche Programmiersprache, die eben auch ihren Benutzern die
Freiheit läßt, ihre Quelltexte bis zur Unleserlichkeit zu verhunzen. Ja,
das geht und man kriegt das ganz einfach auf die bürokratische Weise
hin, indem man saublöde Zusatz-Regeln aufstellt, die das Übliche sind:
Gut gemeint und damit auch hier das Gegenteil von gut gemacht.
Tja, gut gemeint... Da setzen sich Leute hin, um sich sowas wie c_ für
Konstanten per #define auszudenken (und meinen dazu "So weiss ich immer
womit ich es zu tun habe") - oder noch anderen Schmonzes.
Dieser Thread ist ne Sammlung davon.
Aber wer sich schon daran macht, Regeln aufzustellen, der sollte diese
auch zuende denken. Wenn man sowas wie
#define c_ottokar 4711
fordert, um das Konstantenhafte zu dokumentieren, was legt man dann für
ne echte Konstante fest? Rufus hat das ja schon thematisiert:
const int c_i_echt_ottokar = 4711;
So? Oder wie sonst?
Wer Unterschiede so dokumentiert haben will, muß auch für alle im
Sprachumfang erlaubten Fälle etwas Passendes ausdenken.
An so einem Mini-beispiel sieht man deutlich, was für Pappnasen hier
sich an Regulierungen versuchen. Alles Mumpitz, was man deutlich sehen
kann, wenn man diese dummen Gedanken mal konsequent zuende denkt.
Thomas M. schrieb:> doof:ulong i = 0; // Index für Dingse> besser:ulong dingsIdx = 0;
O ha! Und du bist ernstlich der Ansicht, daß man aus dingsIdx mehr an
Verständnis entnehmen kann als aus einen einfachen i ?
Für lokale Zählindizes sind Namen wie i,j,k,l sehr brauchbar, denn sie
halten die Ausdrücke kurz und haben auch nur einen Gültigkeitsbereich
von nur wenigen Textzeilen. Hier mit Namen wie 'lokalerZaehlIndex'
arbeiten zu wollen ist albern. Vielleicht sollten mal alle
C-Programmierer nen Fortran-Kurs belegen.
Dr. Sommer schrieb:> Kennst du eigentlich nur diese eine Oper? Bist du daher einer von diesen> Intellektuellen?
Diese Oper ist leider hier die zuständige Instanz. Deswegen. Ich hätte
mir durchaus hier mehr Leute mit Intellekt gewünscht, aber - nun ja -
man kann ja leider nicht alles haben.
W.S.
Also ich liebe meine Familie und ich hasse den Mann, der mich 3 Monate
lang für sich arbeiten liess ohne zu bezahlen.
Der c_hater hat vermutlich weder eine Liebe noch eine Nemesis, deswegen
fällt er hier so seltsam auf. Irgendwo braucht jeder sein Ventil.
W.S. schrieb:> Ich hätte mir durchaus hier mehr Leute mit Intellekt gewünscht, aber -> nun ja - man kann ja leider nicht alles haben.
Die Welt ist kein Wunschkonzert. Nicht jeder kann deiner kruden
Weltsicht folgen.
Dr. Sommer schrieb:> Die Welt ist kein Wunschkonzert. Nicht jeder kann deiner kruden> Weltsicht folgen.
Nun bin ich erst mal (wieder) überrascht, wieviele Beiträge sich zu so
einem Blödsinn sammeln. Blödsinn, weil wenn privat, dann Jacke wie
Hose...wenn Profi, dann gibt es eine bindende(!) Vorschrift, wie
Programme geschrieben werden müssen!! Wenn nicht, dann reden wir von
einer "Klitsche", die nicht besser als "privat" ist! Und hier melden
sich offensichtlich Repräsentanten aller Kathegorien...zumindes die
"Profis" hätte ich hier nicht erwartet :-)
Gruß Rainer
Marc V. schrieb:> Ich bin mit solcher Bezeichnungsart bisher ganz gut gefahren,> habe auch nach mehreren Monaten keine Probleme zu verstehen, was> es bedeuten soll.
Das glaube ich Dir. Es wird nur noch einfacher, wenn Du Dir redundante
defines sparst. Poste ein Beispiel und ich spendiere Dir eine Kiste
Bier, wenn ich es ohne Redundanz nicht einfacher hinbekomme .
Marc V. schrieb:> ch wollte schon unzählige Male beim ändern bzw. erweitern eines> Programs klüger sein als beim schreiben, ein paar Bytes/Takte einsparen> aber das hat sich ohne entsprechende Kommentare oft genug als ein> Schuss nach hinten erwiesen.
Das sind aber 2 verschiedene Baustellen:
Sinnvolle Namen statt Kommentare (darum ging es)
Kommentieren von abgefahrenen Tricks (darum ging es nicht)
Rainer V. schrieb:> wenn Profi, dann gibt es eine bindende(!) Vorschrift, wie> Programme geschrieben werden müssen!! Wenn nicht, dann reden wir von> einer "Klitsche", die nicht besser als "privat" ist!
Was mich an diesem Forum immer beeindruckt ist das Muster aus diesem
Post: "Ich bin Profi und mache alles superprofessionell. Wenn ihr das
weniger professionell macht, seid ihr doofe Noobs!"
Und dann muss natürlich der nächste kommen und zeigen, dass er noch
professioneller ist als das, weil er noch irgendeine wirre Maßnahme
ergreift, bei der alle die das nicht machen doofe Noobs sind. Bis man
bei irgendsoeinem absurden theoretischen Professionalitätsniveau
angelagt ist, was mit der Realität nur noch wenig und mit der
ursprünglichen Frage und Situation garantiert überhaupt nichts mehr zu
tun hat. Nur damit jeder mal gezeigt hat, wie professionell er ist.
Das lustige daran ist, dass diese Posts immer darauf aus sind, andere
mit der eigenen Erfahrung zu beeindrucken. Diesen Zweck verfehlen sie
aber zuverlässig bei allen Lesergruppen.
Die tatsächlich erfahrenen Leute haben erfahrungsgemäß eine deutlich
entspanntere Haltung zu vielen Dingen, und haben erkannt dass es meist
viele Wege gibt, die zu einem vernünftigen Ergebnis führen. Die genaue
Einhaltung eines einzelnen Konzepts ist dabei meist nicht so wichtig.
Anders gesagt: An dem herummaulen was andere tun ist leicht. Schwieriger
ist, konstruktiv darauf aufzubauen und ausgehend von der Situation des
anderen einen pragmatischen Verbesserungsvorschlag zu machen.
Rufus Τ. F. schrieb:> Es ist bestens bekannt, daß Du Fan von "magic numbers" im Quelltext> bist, denn die lassen sich ja viel einfacher im Datenblatt finden.
Es ist viel schlimmer: Diese "Magic Numbers by W.S." müssen für jeden
ATmega/ATTiny bei einer Portierung auf einen Verwandten der AVR-Familie
neu angepasst werden, weil die Bits öfter mal an anderen Positionen im
Register stecken. Unnötige Arbeit, wenn man die entsprechenden
Preprocessor-Konstanten wie z.B. COM0A0 verwendet.
Allerdings kann man da auch auf die Nase fliegen, da sie nicht immer nur
innerhalb desselben Registers "wandern", sondern manchmal - aber
glücklicherweise selten - auch (je nach AVR) das Register wechseln.
Deshalb hatte ich vor ein paar Jahren mal ein Projekt "Registersichere
Anwendung von Flags" vorgeschlagen. Leider ist es aus Zeitmangel nur bei
einem Konzept geblieben. Es wäre nämlich eine Menge Arbeit gewesen, für
alle AVRs sämtliche Register und deren Flags bzw. Bitgruppen vollständig
und registersicher zu beschreiben. Mit diesem Werkzeug wäre es dann aber
vollkommen egal, in welchem Register die Bits überhaupt stecken.
Siehe auch: Beitrag "Re: AVR-Register als Bitfields"
W.S. schrieb:> Tja, gut gemeint... Da setzen sich Leute hin, um sich sowas wie c_ für> Konstanten per #define auszudenken (und meinen dazu "So weiss ich immer> womit ich es zu tun habe") - oder noch anderen Schmonzes.
Mag für dich und andere Möchtegern- und Copy&Paste Experten Schmonz
sein,
für mich ist es nicht.
W.S. schrieb:> auch zuende denken. Wenn man sowas wie>> #define c_ottokar 4711>> fordert, um das Konstantenhafte zu dokumentieren, was legt man dann für> ne echte Konstante fest? Rufus hat das ja schon thematisiert:>> const int c_i_echt_ottokar = 4711;>> So? Oder wie sonst?
Wie du nicht weisst, wird const ins Flash geschrieben, #define aber
ist einfach eine Anweisung für Präprozessor.
Einen Array mit festen Werten schreibe ich als:
1
staticconstuint8_tc_7seg[]={
2
...
3
}
und kann auch daraus lesen.
So etwas kann man aber mit const nicht machen:
1
constuint8_tc_DatBlkLen=0x3F;// 63 Byt max
2
uint8_tDatBlk[c_DatBlkLen];
mit #define dagegen geht das ohne Probleme.
Etwas, was mit #define definiert wurde, kann mit #undef wieder
rückgängig gemacht werden.
Wenn du mit Copy&Paste aufhörst, wirst du das (kaum wahrscheinlich
aber immerhin zu 0,0001% möglich) auch verstehen.
Frank M. schrieb:> Deshalb hatte ich vor ein paar Jahren mal ein Projekt "Registersichere> Anwendung von Flags" vorgeschlagen. Leider ist es aus Zeitmangel nur bei> einem Konzept geblieben. Es wäre nämlich eine Menge Arbeit gewesen, für> alle AVRs sämtliche Register und deren Flags bzw. Bitgruppen vollständig> und registersicher zu beschreiben.
Könnte man mittlerweile per xslt aus den XML-Beschreibungen machen.
Beim ATmega128RFA1 (und seinen Nachfolgern) hatten wir sowas ins
offizielle Headerfile in der avr-libc reingepackt, aber das hat in der
restlichen AVR-Welt innerhalb Atmel keinen Anklang gefunden. Seit sie
nun all ihren eigenen Device-Support nur noch über ihre "device packs"
verteilen (und damit eigene Headerfiles ausliefern, die nicht denen des
avr-libc-Projekts entsprechen), dürfte das gänzlich den Bach
runtergegangen sein.
W.S. schrieb:> Aber wer sich schon daran macht, Regeln aufzustellen,> der sollte diese auch zuende denken.
Warum denn das? Worauf gründet sich diese Regel? Hast
Du die etwa selbst aufgestellt, ohne sie ganz zu Ende
zu denken?
Es ist sehr sinnvoll, nur häufig auftretende Problemfälle
durch explizit formulierte Regeln zu beseitigen. Andernfalls
löst man eben Probleme, die sich gar nicht stellen -- dafür
gibt es das schöne Wort "Überregulation".
> Wenn man sowas wie>> #define c_ottokar 4711>> fordert, um das Konstantenhafte zu dokumentieren, was> legt man dann für ne echte Konstante fest? Rufus hat> das ja schon thematisiert:>> const int c_i_echt_ottokar = 4711;
Das ist ja wohl eine perverse (="verdrehte") Weltsicht.
Das, was Du als "echte Konstante" bezeichnest, ist
technisch eine vorbelegte Variable.
> Thomas M. schrieb:>> doof:ulong i = 0; // Index für Dingse>> besser:ulong dingsIdx = 0;>> O ha! Und du bist ernstlich der Ansicht, daß man aus> dingsIdx mehr an Verständnis entnehmen kann als aus> einen einfachen i ?
Machst Du Witze?
Wenn eine Routine mit Koordinaten, Codeworten (die
aus zwei verschachtelten Koordinaten bestehen) und
Ternärvektoren (die ihrerseits aus einem Codewort
und einer Maske bestehen) operiert, dann möchte ich
schon gern auf einen Blick sehen, ob jetzt die nächste
Koordinate, das nächste Codewort oder der nächste
Ternärvektor gemeint ist. Das ist nämlich nicht GANZ
dasselbe.
Ich verwende durchaus auch i,j,k für Indizes und
Laufvariablen, aber das nur, wenn aus dem Zusammenhang
offensichtlich ist, worauf sich dieser Index bezieht.
> Für lokale Zählindizes sind Namen wie i,j,k,l sehr> brauchbar, denn sie halten die Ausdrücke kurz und> haben auch nur einen Gültigkeitsbereich von nur wenigen> Textzeilen. Hier mit Namen wie 'lokalerZaehlIndex'> arbeiten zu wollen ist albern.
Überhaupt nicht.
Wenn man Daten aus einem Quelldatenfeld liest, sie
verarbeitet und dann im Ergebnis der Verarbeitung
in eines von mehreren Ergebnisfeldern schreibt, dann
möchte man schon gern wissen, welcher Index in welches
Feld zeigt.
Es gibt mehr als for-Schleifen, und auch in zwei
geschachtelten Schleifen kann man mehr als zwei
Indizes benötigen. Und -- nein, dass lässt sich NICHT
immer vermeiden. Manche Algorithmen SIND eben einfach
kompliziert.
> Ich hätte mir durchaus hier mehr Leute mit Intellekt> gewünscht, aber - nun ja - man kann ja leider nicht> alles haben.
Nun ja. Intellekt liegt im Auge des Betrachters...
A. S. schrieb:> Sinnvolle Namen statt Kommentare (darum ging es)
Ich wiederhole mich ungern, aber dem TO kann man nur sagen, was Profis
machen oder HiWis! Da sich hier lustigerweise sowohl Profis, als auch
HiWis die Klinke in die Hand geben...was soll man da sagen...ich fand
meinen Beitrag zur Mausefalle unterhaltsamer!
Gruß Rainer
Rainer V. schrieb:> wenn Profi, dann gibt es eine bindende(!) Vorschrift, wie> Programme geschrieben werden müssen!! Wenn nicht, dann reden wir von> einer "Klitsche", die nicht besser als "privat" ist!
Ach was erzählst du da für einen Unsinn...
Professionell heißt nur, dass man damit Geld verdient und sagt nichts
über die Qualität aus. Eine wie auch immer geartete, "bindende
Vorschrift, wie Programme geschrieben werden müssen" ist ein
untrügliches Zeichen dafür, dass man es entweder mit inkompetenten
Idioten oder stark regulierten Märkten zu tun hat. Bei uns gibt es
stattdessen mehrere Code-Reviews.
Marc V. schrieb:> Wie du nicht weisst, wird const ins Flash geschrieben, #define aber> ist einfach eine Anweisung für Präprozessor.
Auch "const" wird nicht ins Flash geschrieben, wenn es nicht ins Flash
geschrieben werden muss. Stichwort Compiler-Optimierung.
Marc V. schrieb:> So etwas kann man aber mit const nicht machen:> const uint8_t c_DatBlkLen = 0x3F; // 63 Byt max> uint8_t DatBlk[c_DatBlkLen];> mit #define dagegen geht das ohne Probleme.
Auch das ist seit C99 schlicht falsch. Stichwort Variable Length Array.
Ein typischer Marc.
A. S. schrieb:> Das glaube ich Dir. Es wird nur noch einfacher, wenn Du Dir redundante> defines sparst. Poste ein Beispiel und ich spendiere Dir eine Kiste> Bier, wenn ich es ohne Redundanz nicht einfacher hinbekomme .
Nein, umgekehrt.
Ich spendiere dir eine Kiste Bier, wenn du mir die Redundanz in
meinem Beitrag zeigst.
A. S. schrieb:> Das sind aber 2 verschiedene Baustellen:>> Sinnvolle Namen statt Kommentare (darum ging es)
Nun, so sehe ich das bestimmt nicht.
Sinnvole Namen und Kommentare sowohl für Variablen, als auch
innerhalb des Programms.
Und es geht natürlich um Programme die länger als ein paar Zeilen
sind, mehr als ein Dutzend Variablen haben und wesentlich komplizierter
als BlinkLed Beispiel sind.
Da sind mehrere Dutzend includes, mit mehreren Tausenden von Linien.
Wenn man da etwas ändern muss und dazu erst die Routine xxyyzz finden
muss, um zu sehen was diese Routine überhaupt tut, anstatt dies gleich
aus Kommentar zu sehen oder vielleicht sogar aus dem Namen, z.B:
PutDateTimeToI2C().
Genauso ist es mit Variable xxyyzz.
Das dies alles auch unter der Maus angezeigt wird, ändert nichts an
der Sache.
S. R. schrieb:> Auch das ist seit C99 schlicht falsch. Stichwort Variable Length Array.
Die können aber nicht global/statisch sein. C++ hat übrigens echte
Konstanten, die kann man auch für globale Arrays verwenden oder für
die Definition weiterer Konstanten. Konstanten landen nicht
notwendigerweise separat im Flash, die werden auch ggf. direkt in die
Instruktionen kodiert. Allgemein braucht man in C++ sehr selten Makros,
und das ist ein Vorteil...
S. R. schrieb:> Auch "const" wird nicht ins Flash geschrieben, wenn es nicht ins Flash> geschrieben werden muss. Stichwort Compiler-Optimierung.
Für mich bedeutet const eine readonly Variable, die demzufolge irgendwo
im Flash abgelegt werden muss.
Mit #define wird irgendetwas definiert, ob das ein Ausdruck, String
oder schlicht ein Wert ist, ist absolut egal.
> Marc V. schrieb:>> So etwas kann man aber mit const nicht machen:>> const uint8_t c_DatBlkLen = 0x3F; // 63 Byt max>> uint8_t DatBlk[c_DatBlkLen];>> mit #define dagegen geht das ohne Probleme.>> Auch das ist seit C99 schlicht falsch. Stichwort Variable Length Array.
Ahem.
Kompiliere das mal bitte, so wie es da steht.
Soviel ich und mein Compiler es wissen, geht das nur wenn man Array
lokal deklariert, nicht aber wenn es global deklariert wird.
> Ein typischer Marc.
Eher ein typischer svenska.
Marc V. schrieb:> Für mich bedeutet const eine readonly Variable, die demzufolge irgendwo> im Flash abgelegt werden muss.
Für dich vielleicht. Für z.B. den GCC aber nicht. Der merkt wenn sie
nirgends verändert wird (typischerweise via "static const") und nimmt
sie als fix an, und kodiert die Werte in die Immediates der
Instruktionen direkt hinein.
Marc V. schrieb:> Mit #define wird irgendetwas definiert, ob das ein Ausdruck, String oder> schlicht ein Wert ist, ist absolut egal.
Ja, eine dumme Textersetzung. Das ist ein sehr grobes Werkzeug, da kann
man schnell mal daneben hauen...
Ich habe viel zu viel Zeit damit verbracht, Fehler zu finden, die
dadurch getarnt waren, dass z.B. ein unsigned char u16BlaBlubb hieß,
weil irgendein Profi früher beim Copy&Paste geschlampt hatte. Jahre
später lief u16BlaBlubb aufgrund anderer Änderungen dann über, was laut
Variablenname nicht sein konnte.
Die ungarischen Schniepel waren in dem Projekt "aus Sicherheitsgründen"
vorgeschrieben. Gegen die Funktion mit 1000 Zeilen und 10
verschachtelten Ebenen und die 20 unnötigerweise am Funktionsanfang auf
Vorrat deklarierten Variablen, zwischen denen sich u16BlaBlubb versteckt
hat, hatten die Richtlinien natürlich nichts einzuwenden.
Dr. Sommer schrieb:> Marc V. schrieb:>> Mit #define wird irgendetwas definiert, ob das ein Ausdruck, String oder>> schlicht ein Wert ist, ist absolut egal.>> Ja, eine dumme Textersetzung. Das ist ein sehr grobes Werkzeug, da kann> man schnell mal daneben hauen...
Stimmt, allerdings kann man an vielen Stellen in einem Programm ganz
schnell daneben hauen...
Der einzige Nachteil von #define ist meiner Meinung nach die fehlende
Prüfung auf ev. Fehler, deswegen mag die definition von Makros
fehlerträchtig sein, aber Deklarationen von einfachen Positionen im
Buffer bestimmt nicht.
Marc V. schrieb:> Ich spendiere dir eine Kiste Bier, wenn du mir die Redundanz in> meinem Beitrag zeigst.A. S. schrieb:> wofür c_RcvAdr, wenn es nur offsetof RcvAdr ist? In den meisten fällen> schreibt man doch eh X.RcvAdr. Und wenn man den Index braucht ...> doppelt gemoppelt failed schneller.
Deshalb fragte ich fairer Weise nach einem sinnvollen Beispiel.
Marc V. schrieb:> Der einzige Nachteil von #define ist meiner Meinung nach die fehlende> Prüfung auf ev. Fehler
Das ist ein ziemlicher Nachteil. Dazu kommt dass die keinen Scope haben
und dass man keine Pointer drauf bilden kann. Wenn man C++ nutzt gibt es
keinen Grund diese Nachteile in Kauf zu nehmen; man nimmt einfach
Konstanten und alles ist besser.
Marc V. schrieb:>> Auch "const" wird nicht ins Flash geschrieben, wenn es nicht ins Flash>> geschrieben werden muss. Stichwort Compiler-Optimierung.>> Für mich bedeutet const eine readonly Variable,> die demzufolge irgendwo im Flash abgelegt werden muss.
Das mag für dich so sein, der Compiler sieht das anders.
>> Marc V. schrieb:>>> So etwas kann man aber mit const nicht machen:>>> const uint8_t c_DatBlkLen = 0x3F; // 63 Byt max>>> uint8_t DatBlk[c_DatBlkLen];>>> mit #define dagegen geht das ohne Probleme.>>>> Auch das ist seit C99 schlicht falsch. Stichwort Variable Length Array.>> Ahem.> Kompiliere das mal bitte, so wie es da steht.
1
$cattest.c
2
intmain()
3
{
4
constcharx=0x3F;
5
chartest[x];
6
7
return0;
8
}
9
$gcctest.c
10
$./a.out
11
$
Geht prima, wo ist dein Problem?
> Soviel ich und mein Compiler es wissen, geht das nur wenn man Array> lokal deklariert, nicht aber wenn es global deklariert wird.
Dein geposteter Code enthält kein main(), lässt sich also nicht
kompilieren. Ich habe mir nur die Freiheit genommen, eins einzubauen.
:-)
>> Ein typischer Marc.> Eher ein typischer svenska.
Mir ging es darum, dich darauf hinzuweisen, dass deine beiden Aussagen
maximal Halbwissen sind. Das stört vor allem, weil du immer in
Absolutismen schreibst und selbstverständlich niemals Unrecht hast.
Ein "sowas kann man nicht machen" ist falsch, wenn man es eben doch
meistens machen kann. Und mit Aussagen wie "wie du nicht weißt, gilt X"
blamierst du dich vor allem dann, wenn X nicht uneingeschränkt gilt.
Und genau das ist typisch.
Damit wäre ich dann wieder raus, streitet euch mal weiter. :-)
A. S. schrieb:> A. S. schrieb:>> wofür c_RcvAdr, wenn es nur offsetof RcvAdr ist? In den meisten fällen>> schreibt man doch eh X.RcvAdr. Und wenn man den Index braucht ...>> doppelt gemoppelt failed schneller.>> Deshalb fragte ich fairer Weise nach einem sinnvollen Beispiel.Marc V. schrieb:> Deswegen vielleicht:> union {> USART_RAM sRam;> uint8_t sbuff[5 + c_DatBlkLen + 3];> } Uart_un;> ?
Falls ich:
1
sbuff[offsetof(UartRam,CmdTyp)]
anstatt:
1
sbuff[c_CmdTyp]
verwende, habe ich deutlich mehr an vielen Stellen zu schreiben.
Deklarieren tue ich es dagegen nur einmal ;)
Marc V. schrieb:> falls ich: sbuff[offsetof(UartRam, CmdTyp)] anstatt: sbuff[c_CmdTyp]> verwende, habe ich deutlich mehr an vielen Stellen zu schreiben.> Deklarieren tue ich es dagegen nur einmal ;)
Und warum nicht sRam.CmdTyp? Wie gesagt, Fetzen bringen wenig.
Zumal es trotzdem nicht rechtfertigt, Struktur und define parallel zu
pflegen.
S. R. schrieb:>> Ahem.>> Kompiliere das mal bitte, so wie es da steht.> $ cat test.c> int main()> {> const char x = 0x3F;> char test[x];>> return 0;> }> $ gcc test.c> $ ./a.out> $>> Geht prima, wo ist dein Problem?
Sure.
Und so ?
1
constcharx=0x3F;
2
chartest[x];
3
intmain()
4
{
5
// const char x = 0x3F;
6
// char test[x];
7
8
return0;
9
}
S. R. schrieb:> Mir ging es darum, dich darauf hinzuweisen, dass deine beiden Aussagen> maximal Halbwissen sind. Das stört vor allem, weil du immer in> Absolutismen schreibst und selbstverständlich niemals Unrecht hast.
Tja, eigentlich geht es mir so mit dir.
Joern DK7JB .. schrieb:> Wie benennt ihr eure Variablen eindeutig in der Programmiersprache C> damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine> bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Mir ist nicht ganz klar, wie man auf die Idee kommt, dass es sinnvoll
wäre dies zu tun. Wie andere schon gesagt haben - jeder moderne Editor
zeigt einem den Variablentyp an, wenn man z.B. kurz mit der Maus
drübergeht.
Was immer sinnvoll ist, sind selbstsprechende Namen für Variablen und
Funktionen. Man liest den Namen und schon weiß man um was es geht.
Beispiele:
Vehicle_speed
RoomTemperature
TransmitBuffer[]
display_speed()
temperature_to_Fahrenheit()
isBufferFull()
A. S. schrieb:> Und warum nicht sRam.CmdTyp? Wie gesagt, Fetzen bringen wenig.
Weil sbuff ein Array ist und da ist sbuff[c_CmdTyp] für mich
irgendwie logischer.
sRam ist eine Struktur, da passt sRam.CmdTyp schon.
> Zumal es trotzdem nicht rechtfertigt, Struktur und define parallel zu> pflegen.
Mag sein, aber die sind gleich untereinander deklariert, zusammen mit
allen anderen Variablen fur RS485.
Die Namen sind vielleicht nicht ganz passend gewählt, aber das ganze
funktionert seit vielen Jahren so, warum jetzt ändern ?
S. R. schrieb:> Ach was erzählst du da für einen Unsinn...> Professionell heißt nur, dass man damit Geld verdient und sagt nichts> über die Qualität aus. Eine wie auch immer geartete, "bindende> Vorschrift, wie Programme geschrieben werden müssen" ist ein> untrügliches Zeichen dafür, dass man es entweder mit inkompetenten> Idioten oder stark regulierten Märkten zu tun hat. Bei uns gibt es> stattdessen mehrere Code-Reviews.
Also seid ihr Klitsche nach meinem Verständniss! Und es sagt erst mal
auch gar nichts über die (welche) Qualität aus, was wem möglicherweise
vorgeschrieben wird. Aber wenn mehr als 2 Mann/Frau an einer Software
basteln, dann sind nicht nur die Übergabeparameter festgeschrieben,
sondern auch der Stil der Programmierarbeit überhaupt! Wenn ich von
einem Fuzzi 3 Mal in der Woche Module bekomme, die Fehler erzeugen, dann
schau ich doch mal in dessen Quellcode und wehe, der ist anders als im
Pflichtenheft geschrieben!
Und bitte verzeih', "Code-Review" hört sich für mich an wie
"Therapeutensitzung"
Und klar heisst professionell, dass man Geld verdient...was sonst?
Gruß Rainer
Rainer V. schrieb:> S. R. schrieb:> Bei uns gibt es>> stattdessen mehrere Code-Reviews.>> Also seid ihr Klitsche nach meinem Verständniss! Und es sagt erst mal> auch gar nichts über die (welche) Qualität aus, was wem möglicherweise> vorgeschrieben wird. Aber wenn mehr als 2 Mann/Frau an einer Software> basteln, dann sind nicht nur die Übergabeparameter festgeschrieben,> sondern auch der Stil der Programmierarbeit überhaupt! Wenn ich von> einem Fuzzi 3 Mal in der Woche Module bekomme, die Fehler erzeugen, dann> schau ich doch mal in dessen Quellcode und wehe, der ist anders als im> Pflichtenheft geschrieben!> Und bitte verzeih', "Code-Review" hört sich für mich an wie> "Therapeutensitzung"
Genau! Bäm! Du Noob! Ich Profi! Überhaupt sind nur Leute mit
Pflichtenheft Profis! Und Leute mit anderen etablierten Verfahren, wie
Reviews, sind Noobs, weil ich als Profi das nicht mache und deshalb kann
das gar nicht professionell sein!
Mehrere verschiedene Möglichkeiten, professionell zu arbeiten, sind
grundsätzlich nicht vorstellbar: sonst ist das Feld der Professionalität
ja vielleicht gar nicht total geordnet, und dann kann ich gar nicht ganz
oben in der Hackordnung stehen.
Wie gesagt, dieses Muster ist hier im Forum echt typisch und es hat noch
nie zu einer gewinnbringenden Diskussion geführt, ever. Es nervt nur
alle: die Beteiligten und die Leser gleichermaßen.
In der Softwareentwicklung ist das besonders krass, weil es ohne
Übertreibung hunderte solcher Vorgaben gibt, die von weiten Kreisen als
ein absolutes Muss gehandelt sind, anderen hingegen völlig unbekannt
sind. Deshalb kann man sich da trefflich stundenlang anmaulen, wer der
größere Noob ist weil er keine Versionskontrolle // keine Reviews //
kein Pflichtenheft // keine Style Guide // keine
Dokumentations-Guideline // kein Scrum // kein whaaatever macht.
Projekte wie der Code für die Mondrakete beweisen aber z.B., dass man
sehr wohl ohne Versionskontrollsystem gute Software entwickeln kann ...
Man wird hier nicht dadurch zum Profi, dass man möglichst viele Punkte
auf der Buzzword-Liste abhakt. Weniger ist manchmal sogar mehr.
S. R. schrieb:> Marc V. schrieb:>> Wie du nicht weisst, wird const ins Flash geschrieben, #define aber>> ist einfach eine Anweisung für Präprozessor.>> Auch "const" wird nicht ins Flash geschrieben, wenn es nicht ins Flash> geschrieben werden muss. Stichwort Compiler-Optimierung.
Das geht aber nur, wenn es static ist. Sonst muss sie im Flash stehen,
da eine andere Übersetzungeinheit sie referenzieren könnte.
> Marc V. schrieb:>> So etwas kann man aber mit const nicht machen:>> const uint8_t c_DatBlkLen = 0x3F; // 63 Byt max>> uint8_t DatBlk[c_DatBlkLen];>> mit #define dagegen geht das ohne Probleme.>> Auch das ist seit C99 schlicht falsch. Stichwort Variable Length Array.
Die gibt es aber aus offensichtlichen Gründen nur bei lokalen Variablen.
Tatsächlich gibt es in C gar keine echten Konstanten. #define ist die
beste Annäherung daran. Deshalb wird es auch so oft dafür verwendet. Ein
const int ist keine Konstante, sondern eine Variable, die man nicht
ändern darf. Und ja, das macht einen Unterschied. Beispiel:
1
constinta=0;
2
constintb=a;
Das führt in gcc zu folgendem Fehler:
1
const2.c:20:15: error: initializer element is not constant
Sven B. schrieb:> Genau! Bäm! Du Noob! Ich Profi! Überhaupt sind nur Leute mit> Pflichtenheft Profis!
Mann, dich in einem Vorstellungsgespräch...göttlich...
und Betriebssystem "Hello World"...
Kleiner Mann mit peinlich kleinem Hut...
Rainer
Rainer V. schrieb:> Mann, dich in einem Vorstellungsgespräch...göttlich...
Hmm, meinst du, es wäre besser, dir in einem Vorstellungsgespräch
gegenüber zu sitzen?
Wenn ich es mir aussuchen kann, würde ich wohl Sven jederzeit den Vorzug
geben. Leute mit Dogma mag ich nicht (weder als Chef noch als
Mitarbeiter).
Ich habe schon an so vielen verschiedenen Projekten mitgearbeitet, dass
ich mir die Flexibilität leisten muss, nicht auf einen coding style
festgefahren zu sein. Auch ohne geschriebene coding guides kann man
konsistenten Code produzieren, wenn man nur will. („Ungarische“ Notation
war aber, von paar Win32-Syscalls in AVRDUDE abgesehen, bislang zum
Glück noch nicht dabei.)
Sven B. schrieb:> Projekte wie der Code für die Mondrakete beweisen aber z.B., dass man> sehr wohl ohne Versionskontrollsystem gute Software entwickeln kann ...> Man wird hier nicht dadurch zum Profi, dass man möglichst viele Punkte> auf der Buzzword-Liste abhakt. Weniger ist manchmal sogar mehr.
Na ja, heutzutage kann man tatsächlich nicht mehr professionell ohne
Versionskontrolle entwickeln. Alleine schon wenn man gegenüber dem
Gutachter reproduzierbar nachweisen muss, welcher SW-Stand wann wie zur
Zulassung gebracht werden soll oder wenn man eben Änderungen
(nach-)dokumentieren muss.
Gehört nicht ohne Grund zum "Joel Test" ;-)
https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/
Rolf M. schrieb:>> Auch "const" wird nicht ins Flash geschrieben, wenn es nicht ins Flash>> geschrieben werden muss. Stichwort Compiler-Optimierung.>> Das geht aber nur, wenn es static ist. Sonst muss sie im Flash stehen,> da eine andere Übersetzungeinheit sie referenzieren könnte.
In der Theorie ja. In der Praxis gibt es auch link-time-optimization
(gcc: -flto). Damit funktionieren solche Optimierungen auch über die
Grenzen von Übersetzungseinheiten hinweg.
Axel S. schrieb:>> Das geht aber nur, wenn es static ist. Sonst muss sie im Flash stehen,>> da eine andere Übersetzungeinheit sie referenzieren könnte.>> In der Theorie ja. In der Praxis gibt es auch link-time-optimization> (gcc: -flto). Damit funktionieren solche Optimierungen auch über die> Grenzen von Übersetzungseinheiten hinweg.
Mit switches kann man vieles anders machen und verdrehen, fragt sich
nur ob das auch sinnvoll ist.
Bei einem Teamprojekt steht der switch bei einem Kollegen so, bei
anderen wiederum anders und schon werden aus selbem Code 4 verschiedene
Versionen kompiliert - bei einem funktioniert es, bei anderem (der
zufälligerweise gerade seine Routine geändert hat) nicht und dann
geht die Sucherei los...
Marc V. schrieb:> Axel S. schrieb:>>> Das geht aber nur, wenn es static ist. Sonst muss sie im Flash stehen,>>> da eine andere Übersetzungeinheit sie referenzieren könnte.>>>> In der Theorie ja. In der Praxis gibt es auch link-time-optimization>> (gcc: -flto). Damit funktionieren solche Optimierungen auch über die>> Grenzen von Übersetzungseinheiten hinweg.>> Mit switches kann man vieles anders machen und verdrehen, fragt sich> nur ob das auch sinnvoll ist.> Bei einem Teamprojekt steht der switch bei einem Kollegen so, bei> anderen wiederum anders und schon werden aus selbem Code 4 verschiedene> Versionen kompiliert...
Ernsthaft? Etwas überspitzt gefragt: Redet ihr in diesem "Team" auch
miteinander? Es gibt Dinge die sollte man im Team festlegen.
Marc V. schrieb:> Bei einem Teamprojekt steht der switch bei einem Kollegen so, bei> anderen wiederum anders
Die Switches sollten im Makefile, IDE-Projekt o.ä. stehen und daher bei
allen gleich sein. Ein Grund, Projektdateien eben doch in der
Versionskontrolle einzuchecken, was IMO unberechtigterweise so verpönt
ist.
Dr. Sommer schrieb:> Marc V. schrieb:>> Bei einem Teamprojekt steht der switch bei einem Kollegen so, bei>> anderen wiederum anders>> Die Switches sollten im Makefile, IDE-Projekt o.ä. stehen und daher bei> allen gleich sein. Ein Grund, Projektdateien eben doch in der> Versionskontrolle einzuchecken, was IMO unberechtigterweise so verpönt> ist.
Wie genau meinst du das? Ist die Versionskontrolle allgemein oder
Projektdateien im VCS verpönt?
PS: Der Code sollte natürlich bei allen Compiler-Switches korrekt
funktionieren (außer bei solchen welche die Standard-Konformität
beeinflussen wie -std=gnu99 oder -ffast-math), aber optimale Ergebnisse
darf man ohne die richtigen Optimierungen nicht erwarten. Und in C++ ist
das alles wie gesagt sowieso kein Problem, weil das Konstanten echt
konstant sind.
mh schrieb:> Wie genau meinst du das? Ist die Versionskontrolle allgemein oder> Projektdateien im VCS verpönt?
Projektdateien im VCS einchecken ist verpönt. Wenn die Projekdateien
keine absoluten Pfade o.ä. nutzen ist das aber IMO völlig in Ordnung.
Selbst wenn ein Teammitglied unbedingt eine andere IDE nutzen möchte
(was bei manchen Embedded Plattformen sowieso nicht geht, weil es nur 1
IDE dafür gibt), hat man so immerhin ein "Referenz"-Setup an welches man
sich halten kann. Insbesondere bei Embedded-Plattformen kann das Anlegen
& Konfigurieren von Projekten ziemlich kompliziert sein - da spart das
Einchecken der Projektdatei eine Menge Arbeit.
mh schrieb:> Ernsthaft?
Natürlich,
> Etwas überspitzt gefragt: Redet ihr in diesem "Team" auch> miteinander?
Ja, wir reden miteinander.
> Es gibt Dinge die sollte man im Team festlegen.
Und es gibt Dinge, die soll man nicht mit Gewalt und ohne Grund
ändern, nur damit man beweist, dass irgendein Beitrag in uC.net
nicht stimmt.
So etwas nennt sich Korinthenkackerei und es gibt ein paar
Leute hier, die genau das immer wieder tun, nur um zu beweisen
wie klug und allwissend sie sind und wie unwissend die
anderen.
Dass das genau nichts zum Thema beiträgt und dem TO in keiner
Weise hilft, berührt diese Experten überhaupt nicht, Hauptsache
die anderen werden als unwissend/halbwissend dargestellt...
P.S.
Aussage:
Mercedes ist ein verkehrssicheres Fahrzeug.
Behauptung:
Ja, aber wenn man die Reifen auf 0,5 bar aufpumpt und dann mit
200Km/h auf der Autobahn fährt, stimmt das überhaupt nicht...
Schlussfolgerung:
Die obige Aussage ist falsch und derjenige der das behauptet,
hat überhaupt keine Ahnung von Fahrzeugen und fahren.
Egon D. schrieb:> Es ist sehr sinnvoll, nur häufig auftretende Problemfälle> durch explizit formulierte Regeln zu beseitigen. Andernfalls> löst man eben Probleme, die sich gar nicht stellen -- dafür> gibt es das schöne Wort "Überregulation".
Dieses schöne Wort heißt in der Mechanik und woanders "Überbestimmt" und
ist ein Designfehler. Aber hier handelt es sich gar nicht darum, sondern
es handelt sich um Vollständigkeit. Das ist was grundlegend Anderes.
Und wenn du "nur häufig auftretende Problemfälle" mit Regeln versiehst,
was ist dann deine Regel wert? Garnichts. Entweder ist eine Regel eine
Regel oder sie ist nur heiße Luft - und sollte deshalb schlichtweg
ignoriert werden.
>> const int c_i_echt_ottokar = 4711;>> Das ist ja wohl eine perverse (="verdrehte") Weltsicht.> Das, was Du als "echte Konstante" bezeichnest, ist> technisch eine vorbelegte Variable.
Du redes Unsinn. Das Obengenannte ist eine Konstante. Und zwar eine
echte, die bei einem µC im Flash landet. Im Gegensatz dazu ist alles,
was man per #define macht, eine Textersetzung. Und das was man mit
typedef macht, ist ein Alias.
Versuche du erstmal das logische Denken und das Verwenden korrekter
Wörter zu erlernen, bevor du hier große Töne redest.
W.S.
W.S. schrieb:> Du redes Unsinn. Das Obengenannte ist eine Konstante. Und zwar eine> echte, die bei einem µC im Flash landet.
Nein. Wozu haben wir das gerade diskutiert? Lesen bildet!
W.S. schrieb:>> Das ist ja wohl eine perverse (="verdrehte") Weltsicht.>> Das, was Du als "echte Konstante" bezeichnest, ist>> technisch eine vorbelegte Variable.>> Du redes Unsinn. Das Obengenannte ist eine Konstante.
Nein, ist es technisch gesehen nicht. C kennt in diesem Sinne keine
Konstanten, es ist eine Variable, bei dem Versuche, ihren Wert zur
Laufzeit zu ändern, vom Compiler abgewiesen werden.
C++ kennt echte Konstanten, deshalb darf man sowas dort auch zur
Definition der Größe eines (beliebigen) Arrays benutzen, was man in C
nicht darf:
1
$ cat > foo.c
2
const int a = 42;
3
int b[a];
4
^D
5
$ gcc -xc++ -c foo.c
6
$ gcc -xc -c foo.c
7
foo.c:2:5: error: variably modified ‘b’ at file scope
8
int b[a];
9
^
> Und zwar eine> echte, die bei einem µC im Flash landet.
Primär landet bei einem µC natürlich alles im Flash. Aber obige
Definition besagt noch lange nicht, dass für das Datum explizit Flash
reserviert wird. Der Wert kann genauso gut als Direktwert in einen
Operanden gepackt werden, oder der Compiler benutzt dafür ein Register,
von welchem er weiß, dass dort genau dieser Wert gerade drin steht.
> Im Gegensatz dazu ist alles,> was man per #define macht, eine Textersetzung.
Das hat keiner in Frage gestellt.
Jörg W. schrieb:> Nein, ist es technisch gesehen nicht. C kennt in diesem Sinne keine> Konstanten, es ist eine Variable, bei dem Versuche, ihren Wert zur> Laufzeit zu ändern, vom Compiler abgewiesen werden.
Jörg, das mag am PC drin sein, schließlich kennt Pascal solche
"typisierten Konstanten" ja auch - und am PC liegt schlichtweg alles
im RAM, weswegen man bei Pascal auf sowas sogar schreibend zugreifen
kann, wenn man das tatsächlich will.
Aber bei allen Mikrocontrollern, die ich kenne, landet so eine
"Variable" tatsächlich im Flash und das war's.
Es ist technisch gesehen, eine hart in Silizium gegossene Variable, die
dadurch zu einer echten Konstanten wird, weil sie als "Ding" wirklich
existiert und weil wirklich jeder Schreibversuch zum Fault oder zu nix
führt - auch wenn da kein Compiler meckern würde.
Ich habe sowas reichlich in den USB-Treibern, siehe:
const byte DeviceDescriptor[] =
{ ....
Nochmal:
Wenn jemand schreibt
#define joerg 99
X = joerg + Y;
dann wird in den allermeisten Fällen "joerg" niemals in der Firmware
tatsächlich auftauchen, sondern als Teil eines Maschinenbefehls zu Y
addiert werden.
Wenn jeman aber
const int joerg = 99;
schreibt, dann gibt es mit Sicherheit innerhalb der Firmware eine
zumindest 16 bittige Zahl mit dem Wert 99. Und die kann adressiert
werden wie alle anderen Dinge.
Der Knackpunkt liegt darauf, daß ein #define überhaupt keine Konstante
erzeugt, sondern eine schlichte Textersetzung macht. Der Compiler kriegt
davon nur die finale Zahl mit.
W.S.
W.S. schrieb:> Aber bei allen Mikrocontrollern, die ich kenne, landet so eine> "Variable" tatsächlich im Flash und das war's.
Dann probier doch mal einen STM32F103 aus.
Aus
Da ist nirgendwo eine adressierbare Konstante. Sowohl Adresse als auch
Bitmaske landen direkt als Immediates in den Instruktionen. Genau so
als hätte man ein Makro verwendet. Nur hat man so die diversen Nachteile
des Makros vermieden.
Der Code wurde mit -Os -mpure-code kompiliert. Letzteres ist nötig, um
dem GCC eine andere Optimierung abzugewöhnen, bei welcher er Literal
Pools nutzt; der gezeigte Assembler-Code ist schneller aber größer als
ohne diese Option. Zu Demonstrationszwecken ist es aber hier
interessant, die Version ohne Literal Pool zu sehen.
@ Teilnehmer der Konstantendiskussion:
Ihr redet teilweise aneinander vorbei, weil ihr nicht dazuschreibt,
über welche Sorte von Konstanten ihr redet. In der Softwaretechnik
lässt sich der Konstantenbegriff in (mindestens) vier Kategorien
unterteilen:
- Literale (literals)
- Compilezeit-Konstanten (compile-time constants)
- Compilezeit-konstante Ausdrücke (compile-time constant expressions)
- Nichtüberschreibbare Variablen (immutable variables, Obermenge der
Compilezeit-Konstanten)
Zusätzlich kann man Konstanten jeder dieser drei Kategorien in C per
Makrodefinition neue Namen geben, die damit ebenfalls Konstanten der
jeweiligen Kategorie repräsentieren.
In der Mathematik, von wo der Begriff "Konstante" entlehnt wurde, wird
er nochmals etwas anders genutzt, ebenso in der Physik. Da viele
Softwareentwickler einen mathematischen und/oder physikalischen
Hintergrund haben, wird der Begriff oft auch in diesen Bedeutungen
verwendet.
Wenn ein Softwareentwickler also einfach nur "Konstante" sagt, können
damit sieben verschiedene Dinge gemeint sein. In 6/7 aller Fälle muss
eine Diskussion zwischen zwei Softwareentwicklern in einem Internet-
forum über Konstanten deswegen unweigerlich zu einem nicht konstanten,
sondern eskalierenden Streit führen ;-)
W.S. schrieb:> const byte DeviceDescriptor[] =
Erstens ist ein Array schon mal was ganz anderes, zweitens hast du auch
hier zumindest bei einer recht prominenten µC-Architektur unrecht: da
der AVR für Operationen aus dem Flash andere Befehle braucht als für
Operationen aus dem RAM, werden selbst string literals (die schon seit
C89 "immutable" waren) dort im RAM untergebracht und nur aus dem Flash
initialisiert. Normale Arrays oder structs werden ebenfalls im RAM
untergebracht, auch wenn sie "const" markiert sind. Der Compiler wirft
das zwar in die section ".rodata":
1
$ cat foo.c
2
const struct {
3
int a;
4
char *b;
5
} foo = {
6
.a = 42,
7
.b = "hi"
8
};
9
$ avr-gcc -Os -S foo.c
10
$ cat foo.s
11
.file "foo.c"
12
__SP_H__ = 0x3e
13
__SP_L__ = 0x3d
14
__SREG__ = 0x3f
15
__tmp_reg__ = 0
16
__zero_reg__ = 1
17
.global foo
18
.section .rodata.str1.1,"aMS",@progbits,1
19
.LC0:
20
.string "hi"
21
.section .rodata
22
.type foo, @object
23
.size foo, 4
24
foo:
25
.word 42
26
.word .LC0
27
.ident "GCC: (GNU) 5.4.0"
28
.global __do_copy_data
… aber dem Linker bleibt nichts anderes übrig, als das dann in den RAM
zu packen und aus dem Flash zu initialisieren:
(Adressen ab 0x800000 werden bei der AVR-GCC-Tolchain als RAM behandelt,
Flash ist ab 0.)
So pauschal, wie du das behauptest, passt es eben nicht. Von
Fachbegriffen sehen wir mal ganz ab („Verwenden korrekter Wörter“), denn
spätestens beim C-Standard wirst du dich ziemlich schnell auf
ungewolltes Glatteis begeben …
Yalu X. schrieb:> In 6/7 aller Fälle muss> eine Diskussion zwischen zwei Softwareentwicklern in einem Internet-> forum über Konstanten deswegen unweigerlich zu einem nicht konstanten,> sondern eskalierenden Streit führen ;-)
:-))
Joern DK7JB .. schrieb:> Wie benennt ihr eure Variablen eindeutig in der Programmiersprache C> damit eindeutig ist welcher Typ verwendet worden ist? Gibt es da eine> bewährte Methode oder erfindet da jeder Programmierer das Rad neu?
Ungarische Notation, war lange bei Microsoft Hausideologie mit dem
bekannten Ergebnis. Seit Sie das lassen scheint es besser zu laufen,
kann aber auch Zufall sein. Auf jeden Fall hat es nichts gebracht.
Hab ich auch eine Zeitlang gemacht weil Anfänger. Inzwischen lasse ich
es, kostet unnötig Gehirnschmalz und Zeit und lenktab. Zusätzlich wird
die Software überdefinert was Änderungen erschwert.
Zum lernen aber war es Klasse. Hat das Typenproblem bei mir besser
eingebrannt. Kann jedem empfehlen ungarisch anzufangen und es sein zu
lassen wenn man C besser kann.
W.S. schrieb:>>> const int c_i_echt_ottokar = 4711;>>>> Das ist ja wohl eine perverse (="verdrehte") Weltsicht.>> Das, was Du als "echte Konstante" bezeichnest, ist>> technisch eine vorbelegte Variable.>> Du redes Unsinn.
Das mag der Ungebildete so sehen...
> Das Obengenannte ist eine Konstante.
Du hast Schwierigkeiten mit der Exaktheit, kann das sein?
Ich habe nicht bestritten, dass das eine Konstante ist.
Ich habe darüber gespottet, dass Du das einzige, was
technisch nicht zwingend eine Konstante, sondern eine
vorbelegte Variable ist, als "echte Konstante" bezeichnest.
> Und zwar eine echte, die bei einem µC im Flash landet.
Variablen, vorbelegte Variablen und Konstanten gibt es
schon wesentlich länger als Flash-Speicher; das, was Du
versuchst, ist ein Anachronismus.
> Im Gegensatz dazu ist alles, was man per #define macht,> eine Textersetzung.
Richtig. Und deshalb sind die Sprachelemente, die davon
betroffen sind, zur Laufzeit GARANTIERT konstant -- was
man von vorbelegten Variablen nicht behaupten kann.
> Versuche du erstmal das logische Denken und das Verwenden> korrekter Wörter zu erlernen, bevor du hier große Töne> redest.
Das gebe ich gern zurück und ergänze: Versuche, auf das
Herabsetzen Deines Kontrahenten zu verzichten -- es schadet
Dir selbst mehr als ihm.
HyperMario schrieb:> Ungarische Notation
...
> Hab ich auch eine Zeitlang gemacht weil Anfänger
...
> Zum lernen aber war es Klasse. Hat das Typenproblem bei mir besser> eingebrannt. Kann jedem empfehlen ungarisch anzufangen und es sein zu> lassen wenn man C besser kann.
Au weia. Ist das die masochistische Extremversion von "Lernen durch
Schmerz"? Klar lernt man Sachen besonders nachhaltig, wenn der Irrtum
mit Schmerzen verbunden war. Aber ich würde nicht so weit gehen,
Schmerzen als unabdingbar für einen Lerneffekt anzusehen.
mh schrieb:>> Mit switches kann man vieles anders machen und verdrehen, fragt sich>> nur ob das auch sinnvoll ist.>> Ernsthaft? Etwas überspitzt gefragt: Redet ihr in diesem "Team" auch> miteinander? Es gibt Dinge die sollte man im Team festlegen.
Nein, das sind nur rhetorische Tricks, um nicht feststellen zu müssen,
dass die Welt ein bisschen komplizierter ist. Genauso wie das hier:
Marc V. schrieb:> Aussage:> Mercedes ist ein verkehrssicheres Fahrzeug.>> Behauptung:> Ja, aber wenn man die Reifen auf 0,5 bar aufpumpt und dann mit> 200Km/h auf der Autobahn fährt, stimmt das überhaupt nicht...>> Schlussfolgerung:> Die obige Aussage ist falsch und derjenige der das behauptet,> hat überhaupt keine Ahnung von Fahrzeugen und fahren.
Der erste Teil der Schlussfolgerung ist richtig.
Der zweite Teil ist Unsinn zur Ablenkung.
Eine wunderschöne rhetorische Figur, inhaltlich ist der Pfeil leider an
der Dartscheibe vorbeigeflogen, aber es sollte ja nur zeigen, dass ...
was eigentlich?
Ein typischer Marc eben.
Axel S. schrieb:> Au weia. Ist das die masochistische Extremversion von "Lernen durch> Schmerz"? Klar lernt man Sachen besonders nachhaltig, wenn der Irrtum> mit Schmerzen verbunden war. Aber ich würde nicht so weit gehen,> Schmerzen als unabdingbar für einen Lerneffekt anzusehen.
Es gibt ja Dinge, von denen behauptet wird, dass man sie mal selber
falsch gemacht haben muss, um wirklich zu verstehen, warum es falsch
ist.
Ist wie mit dem Kind, dem auch erst dann wirklich klar wird, warum es
vom Herd wegbleiben soll, wenn es sich mal die Finger an der Herdplatte
verbrannt hat.
Ob das jetzt für die Microsoft'sche ungarische Notation auch gilt, sei
aber mal dahingestellt. Ich hab noch nie verstanden, wozu das gut sein
soll und es deshalb auch noch nie benutzt.
Frage an die Profis von einem reinen Hobbyisten: Redet ihr bei den
Namenskonventionen von den im Verhältnis wenigen globalen Variablen,
oder wendet ihr das auch auf lokale Variablen an?
Eigentlich sind bei mir gefühlt 95% der Funktionen kürzer als zwei
Fensterhöhen, dass der komplette Scope jeder Variablen fast immer
komplett sichtbar ist. Und dann beschränke ich mich meist auf einfache,
kurze und sprechende Namen.
(Damit ist dann 'g' mein einziger echter Präfix, nämlich für globale
Variablen. Ansonsten halt Abkürzungen nObj, iObj etc., aber das sind ja
keine echten Präfixe, sondern Namensteile.)
Walter T. schrieb:> Frage an die Profis von einem reinen Hobbyisten: Redet ihr bei den> Namenskonventionen von den im Verhältnis wenigen globalen Variablen,> oder wendet ihr das auch auf lokale Variablen an?>> Eigentlich sind bei mir gefühlt 95% der Funktionen kürzer als zwei> Fensterhöhen, dass der komplette Scope jeder Variablen fast immer> komplett sichtbar ist. Und dann beschränke ich mich meist auf einfache,> kurze und sprechende Namen.
Ich gehe nach dem Prinzip vor: Je größer der Scope, desto
aussagekräftiger sollten die Namen sein.
> (Damit ist dann 'g' mein einziger echter Präfix, nämlich für globale> Variablen.
Bei mir gehören globale Variablen - so sie denn existieren - zu einem
bestimmten Modul, und dann ist der Name des Moduls der Präfix.
Rolf M. schrieb:> Ich gehe nach dem Prinzip vor: Je größer der Scope, desto> aussagekräftiger sollten die Namen sein.
Hier auch so. Eine strikte Regulierung von Namen haben wir nicht. Die
gängige Konvention, dass Makronamen (zumindest eigene, nicht aus fremdem
Code "geerbte") GROSS geschrieben werden, wird jedoch eingehalten.
Namenspräfixe für globale Namen (sowohl Variablen als auch Funktionen)
werden vorzugsweise nach Subsystem vergeben, damit deren Namen nicht mit
normalem Anwendercode (der diese Subsysteme natürlich kennt) kollidieren
können. Für modulinterne Namen ist das nicht notwendig, die können
keine Namenskollision verursachen.