Wie richtet ihr euren Code ein?
Also wie schreibt ihr Variablen und wie Konstanten?
Typen, Funktionen etc.
Also gibt es hier eine einheitliche Empfehlung?
Also Variablen mit einem v_ voran?
oder Variablen klein Konstanten die ersten beiden Zeichen groß oder so?
Ich nehme alles gross für enum werte und defines, ansonsten überal
klein. Überall snake case. Und alles was global ist bekommt einen
namespace. util_fancy_function, util_other_thing, etc. Wobei meistens
nehme ich da den Projektnamen als Prefix.
Schau dich doch einfach Mal im Internet um bei den ganzen Coding Style
Guides/Rules. Das ist einfach zu viel um das alles hier auf zu zählen.
Ein "kleines" Beispiel:
https://google.github.io/styleguide/cppguide.html
Ich denke man muss für sich bzw. im Team herausfinden was man wie
umsetzen will bzw. am besten findet. Den "richtigen" Weg wird es nicht
geben.
Frag bei Linus nach der richtigen Art zu kommentieren 😂
KArl Fred M. schrieb:> Gibt es das da auch?
Nein. "mani" hat einen cpp-Guide verlinkt, warum auch immer.
Den "richtigen" Coding Style zu finden ist wie die "richtige" Religion
zu finden, es gibt viele verschiedene und deren Anhänger mögen jeweils
die anderen nicht.
Das fängt schon bei Einrückungen an, oder dem Gebrauch von Tabulatoren
und deren Abständen ...
Und ob man lange_namen_mit_underscores mag oder CamelCase, oder ob man
"ungarische Notation" mit Typ-Präfixen mag ... es sind schon Ehen aus
nichtigeren Anlässen geschieden worden.
KArl Fred M. schrieb:> und wie unterscheidet ihr globale von lokalen Variablen
Indem die Komplexität deines Codes klein genug ist, als dass du das
überschauen kannst. Eine lokale Variable erkennst du also daran, dass du
deren Definition bereits auf dem Bildschirm sehen kannst. Außerdem
minimiert man den Gebrauch von globalen Variablen sowieso so weit wie
möglich.
Sauber strukturierter Code ist wichtiger als irgendwelche schrägen
Namenskonventionen, die nur zu Gehirnverrenkungen führen. "Ungarische"
Notation ist das beste Beispiel dafür. Als ich das erste Mal eine
Variable gesehen habe, die mit "lp" anfing, habe ich mich gefragt, was
zum Geier an der Stelle denn der line printer ins Spiel kommt.
DerEinzigeBernd schrieb:> "mani" hat einen cpp-Guide verlinkt, warum auch immer.
Weil die Obermenge von CPP auch auf C angewendet werden kann. Die
Transferleistung die benötigten Dinge heraus zu filtern vorausgesetzt.
Mit einer guten IDE sind Namen Schall und Rauch.
Cursor auf Variable/Funktion: Tooltip zeigt Typ an. Ctrl+Klick: Editor
öffnet die Deklaration. Zurück Taste an der Maus: Editor springt wieder
zurück wo er hergekommen ist. usw.
Gut, wer sich notepad oder nano für Quellcodes antut, der kennt man das
natürlich nicht.
Bei Projekten mit vielen Sourcecode Libs wird man kaum einen
einheitlichen Stil finden. Oder wenn man an einem Projekt als
Teammitglied arbeitet, dann muss man sich an die Regeln des Projektes
halten.
KArl Fred M. schrieb:> Wie richtet ihr euren Code ein?
Wie ein Lager.
Wenn ich nur 3 schrauben brauche und noch nicht klar ist, welche, heißen
die Fächer 1, 2 und 3, analog zu vielleicht i, j und n.
Wenn ich 30 zöllige und 20 metrische habe, sind die Fächer vielleicht
mit M5x20 beschriftet. Wenn alle metrisch sind, entfällt das M.
Konsens ist eigentlich nur, dass nur #defines komplett groß geschrieben
werden. Für alles andere werden die Konstrukte umso komplexer, je mehr
Token es gibt.
Ob Du schraube_m8_20 schreibst, schraube.M8.L20, S8x20 oder
SchraubeM8x20 ist die ersten Jahre egal.
Im großen Lager verlierst Du mit S4711 den Überblick, im kleinen wirst
Du mit achraube_metrisch_steigung_normal_nach_norm_durchmesser8_laenge20
wahnsinnig.
Ich benutze die Regeln, die sonst für Java empfohlen sind:
-Funktionen camelCase, klein beginnend, der Name beginnt meist mit einem
Verb.
-Variablen klein, camelCase, auf keinen Fall solchen Unsinn wie
ungarische Notation.
-Konstanten durchgängig GROSS.
...usw...
KArl Fred M. schrieb:> Also wie schreibt ihr Variablen und wie Konstanten?> Typen, Funktionen etc.
Ganz einfach:
Je größer der Scope, desto aussagekräftiger der Name.
Je kleiner der Scope, desto kürzer der Name.
Normalerweise benutzt man ja irgend ein Framework. Oder schlachtet ein
halbwegs passendes Opensource-Programm aus.
Wenn 3/4 der Klassen aus Qt oder ähnlichem stammen, übernimmt man halt
deren Konventionen. Und wenn man mit kleinen Erweiterungen eines
bestehenden Programmes anfängt, nimmt man deren Schreibweise.
Wenn du das beruflich machst, müsst du eh bei jedem Auftrag andere
Konventionen übernehmen.
(Und dann gibt es noch ein Problem - du fängst mit englischen Namen an,
aber kennst die Übersetzungen der Fachbegriffe nicht. Bekommst Namen,
die aus englischen und deutschen Teilen bestehen).
KArl Fred M. schrieb:> und wie unterscheidet ihr globale von lokalen Variablen z.B.
auch wenn das einige schmerzt nutze ich gerne solche Prefixe wie
g_ Global
s_ Static
p_ Parameter
m_ Member
lokale Variable ohne Prefix
g_, s_ und p_ sind so fiese das die sofort in jedem Code auffallen
aber keine Type-information mit rein wie bei der Ungarische Notation
cppbert schrieb:>> auch wenn das einige schmerzt nutze ich gerne solche Prefixe wie>> g_ Global> s_ Static> p_ Parameter> m_ Member> lokale Variable ohne Prefix>> g_, s_ und p_ sind so fiese das die sofort in jedem Code auffallen>> aber keine Type-information mit rein wie bei der Ungarische Notation
Ich nehme immer noch die ungarische Notation. Gerade bei Sourcecode, den
man lange nicht bearbeitet hat, da hilft das ungemein.
f_Counter = 1;
Da weiss ich sofort, der Counter ist vom Type Float. Da brauch ich nicht
mehr oben bei der Deklaration, oder bei Klassen im .H-File nachschauen.
und wenn dann da steht
i_Index = f_Counter ;
Dann weiss ich, da werden Ints und Floats vermixt, das kann Probleme
geben.
Das hilft mir seit 20 Jahren.
PittyJ schrieb:> Ich nehme immer noch die ungarische Notation. Gerade bei Sourcecode, den> man lange nicht bearbeitet hat, da hilft das ungemein.
Da setze ich den Cursor in den Namen, und links gibt es ein Feld das
einem anzeigt von welchem Typ die Variable ist. Wenn man es überhaupt
mal wissen muß, diese Fälle sind bei mir eher selten.
Ach ja, Strg+Klick auf die Variable springt zu deren Deklaration.
Wühlhase schrieb:> Da setze ich den Cursor in den Namen
Es gibt ja Leute, die beim Lesen von Text immer mit dem Zeigefinger auf
das aktuelle Wort zeigen müssen.
Ich kann meine Augen erheblich schneller bewegen als den Mauszeiger, und
ich fände es lästig, ständig mit der Maus wedeln zu müssen, um dann auch
noch woanders hinsehen zu müssen, um (natürlich leicht verzögert)
Zusatzinformationen angezeigt zu bekommen.
Lesefluss ist etwas anderes.
DerEinzigeBernd schrieb:> Lesefluss ist etwas anderes.
Das ist richtig. Nur ist es m.E. äußerst selten, dass der Typ einer
Variablen strittig ist. Eher, ob sie auf 8 oder 16 Bit beschränkt ist
oder signed/unsigned. Dann bin ich aber ganz schnell bei ellenlangen
präfixen.
Ist man das?
I_32Test
W_16Test2
etc
Aber genau darum geht es mir, dafür schöne Beispiel zu finden, wie das
einige umsetzen. Oftmals entdeckt man dann ja tolle Lösungen
KArl Fred M. schrieb:> Ist man das?> I_32Test> W_16Test2> etc
Wie schriebt ihr so schön?
Guter Lesefluss ist jedenfalls was anderes als so ein Gestotter. ;-)
> schöne Beispiel zu finden, wie das einige umsetzen.
Siehe Yalu: je kleiner der Scope, desto kürzer die Namen. Unmittelbare
Schleifen dann auch gern mit i, j und k. TotalNumberOfFoo (oder
total_number_of_foo) dann eher für globulweite Variablen.
Jörg W. schrieb:> Wie schriebt ihr so schön?>> Guter Lesefluss ist jedenfalls was anderes als so ein Gestotter. ;-)
ICh denke da liegst Du falsch, also damit, mein Beispiel jetzt als
Beispiel zu nehmen.
Mein Beispiel ist sicher nicht ein schönes, daher habe ich diesen Thread
ja überhaut erst gestartet....
Aber über alles andere lässt sich ja diskutieren:-)
KArl Fred M. schrieb:> mein Beispiel jetzt als Beispiel zu nehmen.
Wie mehrfach geschrieben hängt es vom Kontext ab. "Akademische"
Beispiele mit 10 oder 20 Variablen sind praktisch wertlos.
Solange Dein Programm aus wenigen 1000 Zeilen und 100 Token besteht, ist
jedes System OK.
Es ist heute auch völlig OK, zu refakturieren (hier: umzubenennen). Mit
der Lager-Metapher: Der erste Sortimentskasten wird irgendwie
beschriftet. Sobald 10 weitere da sind, ist vielleicht absehbar, wohin
die Reise geht und man versucht, möglichst lesbare, kurze (nicht
kryptische) verständliche Namen mit intuitiver Systematik zu finden. So
dass bei einer neuen Variable praktisch schon vorher klar ist, wie sie
heißen wird.
Sobald sich das Lager dann nochmal verzehnfacht, kann es sein dass alle
Schrauben-Fächer umbenannt werden, damit es übersichtlicher wird.
> ... ist vielleicht absehbar, wohin die Reise geht
Stimmt. Volltreffer!
Von Brooks "Mythical Man-Month" bis Raymonds "Cathedral and the Bazaar"
- ein Punkt hat sich niemals geändert und wird sich nicht ändern: Deinen
ersten Versuch wirfst du sowieso weg.
Du merkst, das ist doch nicht so einfach und für den zweiten Versuch
nimmst du dann Tensorflow, OpenCV und Python. Arbeitest ein Tutorial
durch und übernimmst auch die Konventionen für die Variablennamen.
PittyJ schrieb:> Ich nehme immer noch die ungarische Notation. Gerade bei Sourcecode, den> man lange nicht bearbeitet hat, da hilft das ungemein.>> f_Counter = 1;>> Da weiss ich sofort, der Counter ist vom Type Float. Da brauch ich nicht> mehr oben bei der Deklaration, oder bei Klassen im .H-File nachschauen.
bringt bei Structs oder Klassen relativ schnell gar keinen Mehrwert mehr
oder erschwert nur Refaktoring - primär ist der Scope der Variable
wichtig um zu erkennen welchen Einfluss diese haben kann
PittyJ schrieb:> Ich nehme immer noch die ungarische Notation. Gerade bei Sourcecode, den> man lange nicht bearbeitet hat, da hilft das ungemein.>> f_Counter = 1;>> Da weiss ich sofort, der Counter ist vom Type Float.
Also wenn schon, dann so:
f_Counter = 1.0;
...und dann kann man das f_ auch wiederum weglassen, weil man durch die
Zuweisung sieht dass es hier offensichtlich nicht um einen Integer geht.
:-)
Yalu X. schrieb:> PittyJ schrieb:>> f_Counter = 1;>> Dieser Name ist für mich schon ein Widerspruch in sich :)
Vielleicht will er Tafeln Schokolade zählen, und es sind immer schon ein
paar angefuttert? ;-)
Mark B. schrieb:> f_Counter = 1.0;
nee, da holt man sich double um sie zum float zu machen. Hier macht es
vielleicht nichts aus und der Compiler macht gleich eine float Konstante
raus, aber das fehlende 'f' kann einiges an Codezuwachs und CPU Last
verursachen.
f_counter = 1.0f;
Aber auch nur float wenn der auch halbe Kekse zählen soll.
Wühlhase schrieb:> Ich benutze die Regeln, die sonst für Java empfohlen sind:> -Funktionen camelCase, klein beginnend, der Name beginnt meist mit einem> Verb.>> -Variablen klein, camelCase,
Da stellt sich mir immer die Frage: Wieso mit nem Kleinbuchstaben
beginnend?
Es sind doch Funktions- oder Variablen-"namen". Namen beginnen auch in
Englisch üblicherweise groß?!
Und bezogen auf das namensgebende Kamelbild: verdammt, wer fängt denn
beim Kamelpopo an und geht über die Höcker zum Kopp? Ich meine, so'n
Kamel hat doch ne biologisch geplante Vorzugsrichtung und wir schreiben
auch nicht die Worte von hinten nach vorne.
Versteh ich wieder alles nicht.
Euro schrieb:> Und bezogen auf das namensgebende Kamelbild: verdammt, wer fängt denn> beim Kamelpopo an und geht über die Höcker zum Kopp? Ich meine, so'n> Kamel hat doch ne biologisch geplante Vorzugsrichtung und wir schreiben> auch nicht die Worte von hinten nach vorne.
Viele Kamele gehören Beduinen, und die schreiben von rechts nach links.
Wenn du in der Sprache بلق programmierst, siehst du alles richtig herum:
https://en.wikipedia.org/wiki/Qalb_(programming_language)
:)
Edit: Mist, die Beduinen haben wohl gar keine Groß-/Kleinschrift,
deswegen kommen sie gar nicht in den Genuss von esaClemaC :-(
Ich finde man sollte Programme in einer richtigen Textverarbeitung
schreiben.
Dann kann man lokale Variablen fett schreiben, außer (bei C++)
Membervariablen die schreibt man kursiv.
Globale Variablen werden unterstrichen.
Kommentare werden in Blau geschrieben, und statt
1
#if 0
2
...
3
#endif
wird zur Zeit nicht benötigter Code als durchgestrichen formatiert.
:))
loeti2 schrieb:> Ich finde man sollte Programme in einer richtigen Textverarbeitung> schreiben.> Dann kann man lokale Variablen fett schreiben, außer (bei C++)> Membervariablen die schreibt man kursiv.> Globale Variablen werden unterstrichen.
Das geht in ähnlicher Form sogar ohne Textverarbeitung.
Durch den Standard vorgegebene Schlüsselwörter und Symbole werden
passenderweise in Standardschrift geschrieben, alle selbstdefinierten
Klassen, Funktionen, Argumente sowie globale, lokale und Membervariablen
bekommen jeweils ihre eigene Schriftart:
Udo K. schrieb:> double uₙ₋₁
Mit welchem Compiler geht das? Bei mir regen sich GCC und Clang beide
darüber auf, dass '₋' und '₁' in Identifiern nicht erlaubt seien.
Ganz cool wäre es natürlich, wenn uₙ₋₁ in einem Ausdruck vom Compiler
als u[n-1] interpretiert würde :)
Yalu X. schrieb:>> double uₙ₋₁>> Mit welchem Compiler geht das? Bei mir regen sich GCC und Clang beide> darüber auf, dass '₋' und '₁' in Identifiern nicht erlaubt seien.>> Ganz cool wäre es natürlich, wenn uₙ₋₁ in einem Ausdruck vom Compiler> als u[n-1] interpretiert würde :)
Also für mathelastigen Code ist das schon eine Überlegung wert.
Ich habe das mit dem Visual Studio cl.exe compiliert.
Der clang-cl geht auch unter Win10.
Im neuesten C++ Standard haben sie aber einen Rückzieher gemacht,
und lassen nicht mehr alle gültigen Unicode Identifier Character als
Identifier zu... keine Ahnung was für Wappler dort 2022 solche
Entscheidungen treffen...
für Licht an/aus wären noch bessere Symbole sinnvoll. Nur
Fehlermedlungen vom Compiler sehen kryptisch aus weil da die Symbole
nicht so angezeigt werden.
Aber gut finde ich das auch nicht.
Euro schrieb:> Wühlhase schrieb:>> Ich benutze die Regeln, die sonst für Java empfohlen sind:>> -Funktionen camelCase, klein beginnend, der Name beginnt meist mit einem>> Verb.>>>> -Variablen klein, camelCase,> Da stellt sich mir immer die Frage: Wieso mit nem Kleinbuchstaben> beginnend?> Es sind doch Funktions- oder Variablen-"namen". Namen beginnen auch in> Englisch üblicherweise groß?!> Und bezogen auf das namensgebende Kamelbild: verdammt, wer fängt denn> beim Kamelpopo an und geht über die Höcker zum Kopp? Ich meine, so'n> Kamel hat doch ne biologisch geplante Vorzugsrichtung und wir schreiben> auch nicht die Worte von hinten nach vorne.
Das ist in C zwar weniger wichtig, aber in Java hast du damit eine gute
Trennung zwischen Klasse und Instanzvariable. Klassen sind normalerweise
ja Nomen, die werden in der weltweit häufig genutzen Lingua Franca
Deutsch groß geschrieben. ;)
Eine einheitlich sinnvolle Schreibweise für Variablen ist schwierig.
Booleans beginnen oft mit einem Verb oder können nur Verb sein
(isLocked, locked, ...), bei Zahlen oder Strings ist das aber meistens
anders (amountOfFails, motorCurrent, userName, ...).
Egal wie man es macht, so richtig richtig ist es nie, da kann man
genausogut alles klein schreiben.
Funktionen/Methoden drücken oft eine Tätigkeit aus, bestehen
sinnvollerweise aber oft aus mehr als einem Verb und beinhalten oft ein
Objekt (im grammatikalischen Sinne von Subjekt, Verb und Objekt)
(flush(), getFoo(), setFoo(), sayHelloWorld(), ...)
In camelCase-Schreibweise erspart man sich den lästigen '_', den ich
persönlich gräßlich finde, und hat dennoch eine Trennung zwischen den
Namensbestandteilen. Und fangen trotzdem klein an.
Aber so richtig weiß man solche Schreibweisen erst zu schätzen, wenn man
mal einige 10.000 Zeilen Code damit geschrieben hat. Nicht jede
Konvention ist sinnvoll, aber die von Java gefällt mir gut genug um sie
auch in C zu verwenden.
Walter T. schrieb:> Boolesche Variablen ā la "isLocked" fand ich immer unlogisch, weil das> wichtigste hinten steht.
Ich ziehe mir die Variablennamen auch nicht nach subjektiv empfundener
Wichtigkeit aus dem Fingern. Zwischen Verb und Adverb die Wichtigkeit
auszudifferenzieren führt auch zu nichts: ob du 'is' oder 'locked'
wegnimmst, beides ist sinnentstellend.
In erster Linie versuche ich Code so zu schreiben, daß ich ihn wie
Fließtext lesen kann. Das erspart überflüssige Kommentare im Quelltext.
Zu stark (ab-)gekürzte Variablennamen führen, abhängig von der
Dozenten-Köpergröße, zu Punktabzug:
"zwerg" für ZwischenErgebnis oder
"dwarf" für "data without any reasonable function"
Ich finds ne gute Idee - auch in C - die gute alte Groß/Kleinschreibung
zu nutzen: Klassen/structs groß schreiben (modellieren ja meist
Objekte), Operationen/Funktionen (Tätigkeiten/Verben) auf diesen
Objekten klein.
Nen Satz wie: es existiert ein Auto, bei dem der Starter betätigt wird
modelliert sich z.B. zu:
Auto a;
a.startEngine();
a.engageClutch();
a.shiftUp();
a.disengageClutch();
a.stopEngine();
irgendsowas halt. In C könnte halt Auto ne struct sein und als Parameter
rein:
startEngine(&a);
engageClutch(&a);
shiftUp(&a);
disengageClutch(&a);
stopEngine(&a);
-> guter Startpunkt ist Google Style, gibt aber auch ne Reihe andere,
geeignete.
tut nix zur sache schrieb:> Ich finds ne gute Idee - auch in C - die gute alte Groß/Kleinschreibung> zu nutzen: Klassen/structs groß schreiben (modellieren ja meist> Objekte), Operationen/Funktionen (Tätigkeiten/Verben) auf diesen> Objekten klein.
Sollte man nach dieser Logik nicht auch Variablen, insbesondere
Instanzen von Klassen, mit einem Großbuchstaben beginnen lassen? Bei
Enum-Elementen könnte man die Groß-/Kleinschreibung davon abhängig
machen, ob es sich um Substantive oder Adjektive handelt, also etwa so
(auch wenn das nicht mein Stil ist):
1
enumVehicleType{Car,Truck,Bike};
2
enumVehicleColor{black,white,red};
3
4
structVehicle{
5
VehicleTypeType;
6
VehicleColorColor;
7
};
8
9
VehicleVehicle;
Alles nicht so einfach :)
Anders als in C und C++ nimmt einem Haskell zumindest bei der
Groß-/Kleinschreibung des Anfangsbuchstabens von Identifiern die
offensichtlich so schwere Entscheidung ab und regelt dies ganz
diktatorisch per Sprachspezifikation:
Mit einem Großbuchstaben beginnen die Namen von
- Modulen
- Typklassen
- Typkonstruktoren
- Typen
- Datenkonstruktoren
Mit einem Kleinbuchstaben beginnen die Namen von
- Typvariablen
- Funktionen
- Variablen
Wer gegen diese Regel verstößt, bekommt sofort Schelte vom Compiler :)
Für die restlichen Zeichen in Identifiern gibt es zwar keine strikte
Regel, aber eine allgemein akzeptierte Konvention, nämlich Camel Case
bzw. Pascal Case, so dass einem auch dort die Entscheidung abgenommen
wird.
Richtige Programmiersprachen haben sowieso alles groß geschrieben, außer
Strings, aber die hießen dort auch noch "Hollerith-Konstante". ;-) In
der beliebtesten (:-) Form dann auch gern als
1
22HDas ist eine Konstante aber das gehoert nicht mehr dazu
MaWin schrieb:> Meine Religion verbietet Camel-Case. Was nun?
Wechsle entweder die Religion oder die Programmiersprache.
Moment: ist eine Programmiersprache nicht eh eine Religion? Bei dir ganz
sicher.
Jörg W. schrieb:> Moment: ist eine Programmiersprache nicht eh eine Religion? Bei dir ganz> sicher.
Da sieht man einmal wieder gut, dass du mich vollkommen falsch
einschätzt.
Aus dem Alter in dem man religiöse Kriege um die "richtige"
Quellcodeformatierung führt bin ich lange raus.
Viel wichtiger, als die "richtige" Formatierung zu wählen, ist eine
konsistente Formatierung beizubehalten.
tut nix zur sache schrieb:> Nen Satz wie: es existiert ein Auto, bei dem der Starter betätigt wird> modelliert sich z.B. zu:
Was ist dann z.B. mit Properties in C#?
Z.B.: car.motorAlign = front; (???)
Ok, da liegt ein getter/setter hinter, aber der ist schon klein
geschrieben.
Walter T. schrieb:> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll? Immer noch 80> Zeichen, 100 Zeichen oder gar 120 Zeichen?
In meinen Projekten gibt es keine harte Grenze, aber länger als 120
sollte man möglichst vermeiden. Soll heißen: Wenn die Zeile mal 122
Zeichen lang ist, muss man sie nicht gleich irgendwie auf zwei Zeilen
verteilen, nur weil die Grenze halt bei 120 liegt. Generell finde ich
Regeln, die ein hartes Limit setzen, selten sinnvoll.
Die harte Begrenzung auf 80 war im letzten Jahrtausend noch sinnvoll,
als noch im Textmodus gearbeitet wurde, wo eben nur genau 80 Zeichen pro
Zeile auf den Bildschirm passten.
Walter T. schrieb:> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll? Immer noch 80> Zeichen, 100 Zeichen oder gar 120 Zeichen?
So breit, das zwei Listings nebeneinander und die IDE auf meinen 27"
passt, ohne das ich ne Lupe brauche oder großartig Horizontal scrollen
muss. Wenn's mir zu bunt wird, breche ich die Zeile um. Ne wirklich
feste Länge hab ich nicht.
Walter T. schrieb:> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll?
In meiner Religion müssen Zeilen immer exakt 98 Zeichen lang sein. Nicht
länger und nicht kürzer!
Aber im Ernst: Es spielt gar keine Rolle. Wenn mir dein Format nicht
passt, dann formatiere ich es mit einem der seit Jahrzehnten
existierenden Code-Reformatiertools um.
Wenn du gerne horizontal scrollst, dann mache es bitte.
Ich mache es nicht und begrenze mich deshalb auf in etwa 90-100 Zeichen.
MaWin schrieb:> Aber im Ernst: Es spielt gar keine Rolle. Wenn mir dein Format nicht> passt, dann formatiere ich es mit einem der seit Jahrzehnten> existierenden Code-Reformatiertools um.
Das ist wenig sinnvoll, wenn man mit mehreren Leuten an einem
gemeinsamen Repository arbeitet.
> Wenn du gerne horizontal scrollst, dann mache es bitte.
Bei mir bricht der Editor es bei der Darstellung einfach um, wenn man
über den Rand kommt. Das ist zwar nicht sehr hübsch, erspart einem aber
das Scrollen. Wobei ich zumindest mit dem Desktop-Monitor bei 120
Zeichen noch problemlos zwei Files nebeneinander bekomme. Auf dem
Bildschirm des Laptop reicht's dann aber nicht mehr ganz.
Ich glaube, wir bleiben bei C.
Ich habe üblicherweise 100 Zeichen als Grenze. Dann passen auf einem
38-Zoll-Monitor noch drei Merge-Fenster nebeneinander.
Das Problem: Variablennamen sind heute deutlich länger als, damals, als
Variablennamen allerhöchstens zwei Buchstaben Länge haben sollten, und
dann ist mit einem billigen y = (x+x0)*a; schon ruck-zuck eine ganze
Zeile übervoll. Beispiel:
Noch schlimmer werden Funktions-Signaturen. Das sind fast immer
Mehrzeiler, obwohl mir nirgendwo etwas auffällt, was sinnvoll gekürzt
werden sollte. Willkürliches Beispiel aus dem Fenster vor mir:
Rolf M. schrieb:> Das ist wenig sinnvoll, wenn man mit mehreren Leuten an einem> gemeinsamen Repository arbeitet.
Genau. Denn wie ich bereits schrieb:
MaWin schrieb:> Viel wichtiger, als die "richtige" Formatierung zu wählen, ist eine> konsistente Formatierung beizubehalten.Walter T. schrieb:> Das Problem: Variablennamen sind heute deutlich länger als, damals
Das ist natürlich auch nur ein Problem der Selbstdisziplin.
Walter T. schrieb:> int_fast8_t menu_standard(constflash Menuitem_t Menudata[],> constflash Menuconfig_t *Menuconfig,> int_fast8_t selectedItem);
1
#define cflash constflash // irgendwo zentral.
2
3
int8_tmenu_std(cflashMenuItem_tdata[],
4
cflashMenuConf_t*cfg,
5
int8_tselItem);
Die ganze fast-Typen-wichserei bringt praktisch keinen Laufzeitgewinn,
aber verschlechtert die Lesbarkeit enorm und birgt auch Möglichkeiten
für versteckte Fehler.
Die "fast"-Typen sind für mich eine Absichtserklärung: "Ich brauche 8
Bit Breite, aber ich verlasse mich nicht auf irgendwelchen Overflow."
Welche versteckten Fehler können sie erzeugen?
Walter T. schrieb:> Die "fast"-Typen sind für mich eine Absichtserklärung: "Ich brauche 8> Bit Breite, aber ich verlasse mich nicht auf irgendwelchen Overflow."
Dann nimm doch einfach 'int'. Weniger Tipparbeit, auch mindestens 8 Bit
breit und von der tatsächlichen Größe her auch implementation defined.
> Welche versteckten Fehler können sie erzeugen?
Wenn dein Code eben doch Überläufe erzeugt, weil er zum Beispiel Bugs
hat, dann hängt das Verhalten und ob UB auftritt von der tatsächlichen
Größe ab. Schwere Debugbarkeit. Schlechtere Lesbarkeit. Außerdem
unterscheidet sich das Cast-Verhalten und das Ergebnis wird
Plattformabhängig (s.u.). Fast-Typen haben praktisch nur Nachteile.
Du könntest hier auch einfach 'int' verwenden. Oder halt uint8_t.
Wenn jetzt eine Plattform sich entscheiden würde int_fast16_t
tatsächlich als int16_t zu implementieren, was ja erlaubt ist und z.B.
auf AVR8 wahrscheinlich der Fall sein dürfte, dann wäre die Ausgabe:
Walter T. schrieb:> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll? Immer noch 80> Zeichen, 100 Zeichen oder gar 120 Zeichen?
Das hängt (wie alles andere) von Werkzeug und Arbeitsstil ab.
Mancher Code ist im "Blocksatz" besser lesbar. Das füllen von 10 structs
mit gleichen, fortlaufenden und systematischen Inhalten kann im
Blocksatz viel einfacher kontrolliert werden. Also 10 lange Zeilen
untereinander. Das gleiche bei manchen if/else.
Wenn dein Werkzeug in für Dich üblicher konfug 80 Zeichen darstellt,
kann es beim meisten Code sinnvoll sein, die Kommentare hinter die
Anweisung zu schreiben.
Bei 30 Zeichen (weil zumeist im Debugger und 3 Quelltexte gleichzeitig
oder einfach schlechte Augen) dann halt über der Zeile.
Die festen Grenzen kommen aus Zeiten fester Werkzeuge (Lochkarte,
Textmonitor)
Ich verstehe Deinen Standpunkt in Bezug auf die "fast" und
"least"-Datentypen. Ich muss mal überlegen, ob ich künftig die gleichen
Schlüsse daraus ziehe.
Wie sieht es bei den Kurznamen aus?
Was mir aufgefallen ist: "Config" wurde auf zwei verschiedene Arten
abgekürzt, nämlich "Conf" und "Cfg". Ein weiterer Kandiat, den ich schon
gesehen habe, wäre "Cnf", noch nie gesehen in freier Wildbahn: "Cnfg".
Für mich war der Schluss daraus: "Schreib es aus. Du kannst schnell
tippen. Du kannst schnell lesen. Das ist am wenigsten fehlerträchtig."
Wie hält man das konsistent? Gibt es da einen Thesaurus, mit denen die
Profis gängige Bezeichnungen abkürzen?
Walter T. schrieb:> Was mir aufgefallen ist: "Config" wurde auf zwei verschiedene Arten> abgekürzt, nämlich "Conf" und "Cfg".
Sehr gut erkannt. War mir gar nicht aufgefallen. Das sollte natürlich
noch verbessert werden.
Die genaue Wahl, ob conf, cfg, cnf oder meinetwegen auch config finde
ich dabei gar nicht so wichtig. Eher, dass es überall konsistent und
gleich ist. (Was ja hier bei mir nicht der Fall war.)
Variablenlängen addieren sich ja oft auf in der Zeile. Deshalb finde ich
es wichtig in Variablennamen nicht unnötig zu "schwätzen". Das Wort
"menu" in Variablennamen finde ich in der Funktion, bei der es nur um
Menüs geht, beispielsweise unnötig. Die Variablennamen "menuConfig" und
"config" sind vom Informationsgehalt in dem Kontext gleichwertig, aber
config ist kürzer und deshalb würde ich es wählen (und dann ggf. noch
weiter abkürzen zu etwa conf oder cfg.)
Walter T. schrieb:> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll? Immer noch 80> Zeichen, 100 Zeichen oder gar 120 Zeichen?
Als Alleinprogrammierer nehme ich 80 Zeichen als Grenze, wobei ich mit
Kommentaren auch mal darüber hinaus gehe. Insbesondere bei
Member-Variablen von Klassen, da habe ich die Variablen gerne als Liste
untereinander, das ist mir wichtig für den Überblick. Die Variablen
bekommen dann eine kurze Beschreibung, die dann in der gleichen Zeile
dahinter steht und die 80 Zeichen reichen dann oft nicht. Macht aber ja
nichts, die Beschreibung schaut man nicht oft an, da kann man auch mal
nach rechts scrollen oder das Fenster größer ziehen.
Mit "echtem" Code gehe ich aber nie über die 80 Zeichen.
MaWin schrieb:> Rolf M. schrieb:>> Das ist wenig sinnvoll, wenn man mit mehreren Leuten an einem>> gemeinsamen Repository arbeitet.>> Genau. Denn wie ich bereits schrieb:>> MaWin schrieb:>> Viel wichtiger, als die "richtige" Formatierung zu wählen, ist eine>> konsistente Formatierung beizubehalten.
Du hast aber auch geschrieben:
MaWin schrieb:> Wenn mir dein Format nicht passt, dann formatiere ich es mit einem der> seit Jahrzehnten existierenden Code-Reformatiertools um.
Und das setzt eben voraus, dass ihr nicht gemeinsam an dem Code
arbeitet.
MaWin schrieb:> Walter T. schrieb:>> Die "fast"-Typen sind für mich eine Absichtserklärung: "Ich brauche 8>> Bit Breite, aber ich verlasse mich nicht auf irgendwelchen Overflow.">> Dann nimm doch einfach 'int'. Weniger Tipparbeit, auch mindestens 8 Bit> breit und von der tatsächlichen Größe her auch implementation defined.
Aber auf einem AVR halt langsamer und speicherintensiver.
> Wenn dein Code eben doch Überläufe erzeugt, weil er zum Beispiel Bugs> hat, dann hängt das Verhalten und ob UB auftritt von der tatsächlichen> Größe ab. Schwere Debugbarkeit. Schlechtere Lesbarkeit. Außerdem> unterscheidet sich das Cast-Verhalten und das Ergebnis wird> Plattformabhängig (s.u.).
Das gilt für int aber auch.
> Fast-Typen haben praktisch nur Nachteile.
Sie haben den Vorteil, dass du nicht eine feste Größe erzwingst, wo du
sie gar nicht brauchst. Es gibt präziser an, was du benötigst. Und außer
bei Hardware-Registern und Binärformaten braucht man nur selten Typen,
die eine ganz bestimmte feste Größe haben müssen. Stattdessen hat man
Mindestanforderungen und möchte eben entweder einen auf geringe Laufzeit
oder einen auf minimale Größe optimierten Typ, je nachdem, ob man jetzt
in einer Schleife 100 Millionen mal ein und das selbe Objekt des Typs
beschreibt oder ob man ein Array aus 100 Millionen Objekten benötigt.
Genau das drücken int_fast*_t und int_least*_t aus.
> Du könntest hier auch einfach 'int' verwenden. Oder halt uint8_t.> #include <stdint.h>> #include <stdio.h>> int main(void)> {> uint16_t a = 0xFFFF;> int16_t b;> int_fast16_t c;> b = (int16_t)a;> c = (int_fast16_t)a;> printf("%d %d\n%d %d %d\n", sizeof(b), sizeof(c), (int)a,> (int)b, (int)c);> }>> Ausgabe:2 8> 65535 -1 65535>> Wenn jetzt eine Plattform sich entscheiden würde int_fast16_t> tatsächlich als int16_t zu implementieren, was ja erlaubt ist und z.B.> auf AVR8 wahrscheinlich der Fall sein dürfte, dann wäre die Ausgabe:2 2> 65535 -1 -1
Dein Argument ist also, dass fehlerhafte Werte auftreten können, wenn
dein Programm Fehler hat? Im übrigen hättest du mit int exakt das selbe
Problem. Denn auch der ist in der Regel auf dem AVR 16 Bit breit und auf
dem PC größer.
MaWin schrieb:> Variablenlängen addieren sich ja oft auf in der Zeile. Deshalb finde ich> es wichtig in Variablennamen nicht unnötig zu "schwätzen". Das Wort> "menu" in Variablennamen finde ich in der Funktion, bei der es nur um> Menüs geht, beispielsweise unnötig. Die Variablennamen "menuConfig" und> "config" sind vom Informationsgehalt in dem Kontext gleichwertig, aber> config ist kürzer und deshalb würde ich es wählen (und dann ggf. noch> weiter abkürzen zu etwa conf oder cfg.)
Das entspricht auch die Regel, dass Namen umso aussagekräftiger sein
sollen, je größer der Scope ist, in dem sie genutzt werden.
Rolf M. schrieb:> Aber auf einem AVR halt langsamer und speicherintensiver.
Was meinen Vorschlag die Typen mit plattformunabhängiger Größe zu
verwenden nur untermauert. Mein Vorschlag zu int statt int_fast8_t war
nur, falls man unbedingt einen Typ mit plattformdefinierter Größe haben
will.
Rolf M. schrieb:> Dein Argument ist also, dass fehlerhafte Werte auftreten können, wenn> dein Programm Fehler hat?
Nein. Das habe ich nie gesagt. Ich habe das Gegenteil gesagt.
Ich sagte, dass Fehler mit int_fast8_t (und Konsorten) leichter zu
produzieren sind und schwerer zu finden sind, als mit intX_t.
Dass das Programm fehlerhaft ist, ist unbestritten und Absicht.
Es ging mir darum warum das Programm fehlerhaft ist.
Rolf M. schrieb:> Im übrigen hättest du mit int exakt das selbe Problem.
Ganz genau. Deshalb Typen fester Breite.
Du hängst dich hier am int fest, ohne verstanden zu haben, was ich damit
in einem Nebensatz gesagt habe. Das war ein völlig unwichtiges
Randdetail in meiner Argumentation.
Wir sind einer Meinung, nur du hast es noch nicht bemerkt.
Mark B. schrieb:> Walter T. schrieb:>> Noch schlimmer werden Funktions-Signaturen. Das sind fast immer>> Mehrzeiler>> Und das Problem daran ist... was genau?
Das ist eine gute Frage, und ich habe jetzt mehr als 10 Minuten darüber
nachgedacht, ohne eine echte Antwort zu finden.
Es erzeugt ein.....Unwohlsein.
Vielleicht liegt es nur daran, dass in allen Büchern, die ich
mittlerweile über Softwareentwicklung gelesen habe, alle
Funktions-Signaturen grundsätzlich schicke Einzeiler sind, und das sich
als gefühlter SOLL-Zustand eingenistet hat.
Aber vielleicht ist das tatsächlich nur der Unterschied zwischen der
schönen Theorie und der schmutzigen Praxis.
Teo D. schrieb:> Walter T. schrieb:>> Welche Zeilenlänge ist eigentlich heutzutage sinnvoll? Immer noch 80>> Zeichen, 100 Zeichen oder gar 120 Zeichen?>> So breit, das zwei Listings nebeneinander
Besser drei (für Three-Way-Merge). Bei einer minimalen horizontalen
Bildschirmauflösung von 1920 Pixel sind gerade etwa 3×80 Zeichen
möglich, ohne dass die Zeichen pixelig wirken. Für Programme in C,
Python und Haskell sind die 80 Zeichen auch völlig ausreichend, bei C++
wird es etwas grenzwertig.
Wenn ich in Projekten mit anderen arbeite und es dafür einen Style-Guide
gibt, richte ich mich natürlich nach diesem. Der Editor wird dann
automatisch mit den jeweiligen Parametern gestartet. Da ist die maximale
Zeilenlänge dann oft 120, was auch für C++ adäquat ist und auf einem
Full-HD-Display immerhin noch zwei Listings nebeneinander zulässt.
Zeilenumbrüche sollte man nur dort machen, wo es auch logisch sinnvoll
ist. Gibt es in einer langen Zeile keine guten Umbruchpositionen, ist es
besser, eine lange, komplizierte Anweisung in zwei einfachere zu
zerlegen.
Sinnvoll umgebrochene Zeilen oder in mehrere Einzelanweisungen
aufgeteilte Anweisungen habe auch mehr Struktur. Eine überlange Zeile
ist in sich strukturlos und muss deswegen vom Leser mit dem Auge geparst
werden, was auf Dauer sehr anstrengend sein kann.
Von Formatierungstools, die an den Zeilenumbrüchen herumdoktern, halte
ich nicht viel, weil sie die Zeilen irgendwo, aber selten an logisch
sinnvollen Stellen umbrechen.
Überlange Zeilen sind oft die Folge von überlangen Variablennamen.
Weiter oben habe ich geschrieben:
Yalu X. schrieb:> Je größer der Scope, desto aussagekräftiger der Name.>> Je kleiner der Scope, desto kürzer der Name.
Setzt man Variablen mit weitem Scope (insbesondere globale Variablen)
mit Bedacht ein, fördert das nicht nur die allgemeine Übersichtlichkeit,
sondern vermeidet auch überlange Zeilen.
KArl Fred M. schrieb:> @PittyJ> Ja, mir gefällt die Ungarische Notation bislang auch am besten
Wer sich schon mal darauf verlassen hat, dass die Prefixe der
ungarischen Notation auch korrekt verwendet werden (und z.B. bei
Typänderungen auch nachgezogen werden) um dann nach einiger Zeit der
Fehlersuche festzustellen zu müssen, dass die inkorrekt war, wird sie
nie wider verwenden.
Zentrale Regel beim Entwickeln: Redundanz die manuell abgeglichen wird
muss vermieden werden. Da die ungarische Notation dies nicht tut ist sie
Mist.
Michael
Ich schreibe meine Programme immer in SciTE in Proportionalschrift.
(Da sich ein Compiler der mit Formatierung einer Textverarbeitung
zurecht kommt noch nicht durchsetzen konnte. Siehe mein letzter Beitrag
im Thread)
Deshalb ist die maximale Zeilenlänge von der Breite der genutzten
Buchstaben abhängig.
Als kleiner Nachteil sehe ich dass das Untereinanderstellen z.B. von
Parametern bei Funktionen schwierig ist. Siehe hier die Zeile mit
unsigned long long c), da muß man mit Leerzeichen kreativ werden.
[tab][tab]void realBigfooFunction(unsigned long long a, unsigned long
long b,
[tab][tab][spc][spc]...[spc][spc][spc]unsigned long long c) {
[tab][tab][tab]...
[tab][tab]}
Walter T. schrieb:> Es erzeugt ein.....Unwohlsein.
Nicht nur. He nach Werkzeugen kann es sein, dass Einzeiler Vorteile
haben. Z.b. wenn man die Funktion per Textsuche sucht (warum auch immer)
und das Ergebnis im suchfenster nur einzeilig ist.
Bei SW kommt es nur auf Lesbarkeit an. Und Lesbarkeit ist auch davon
abhängig, ob man Begriffe direkt erklärt bekommt (suche, mouseover, ...)
oder erst dahin springen muss.
KArl Fred M. schrieb:> und wie unterscheidet ihr globale von lokalen Variablen z.B.
Lokale Variablen immer klein und so kurz wie möglich. Oft vorkommende
Standardvariablen wie i, s und t erleichtern die Wiederverwertung.
Globale Variablen fangen groß an, gerne als CamelCase, ebenso
Funktionen, die globalen Variablen verändern. Es gibt keinen Grund,
keine Variablen groß zu beginnen, und die deutliche Unterscheidung von
lokalen und globalen Variablen halte ich für wesentlich, um schnell
wieder den Überblick zu finden.
Walter T. schrieb:> Noch schlimmer werden Funktions-Signaturen. Das sind fast immer> Mehrzeiler, obwohl mir nirgendwo etwas auffällt, was sinnvoll gekürzt> werden sollte. Willkürliches Beispiel aus dem Fenster vor mir:> int_fast8_t menu_standard(constflash Menuitem_t Menudata[],> constflash Menuconfig_t *Menuconfig,> int_fast8_t selectedItem);> Testweise habe ich mal 120 Zeichen ausprobiert, aber das ist> gleichzeitig vom Lesefluss zu breit und für Funktionssignaturen zu> schmal.
Ich formatiere sowas gerne so:
1
int_fast8_tmenu_standard(
2
constflashMenuitem_tMenudata[],
3
constflashMenuconfig_t*Menuconfig,
4
int_fast8_tselectedItem
5
);
Das kann man selbst bei 10 Argumenten noch gut lesen.
MaWin schrieb:> Rolf M. schrieb:>> Dein Argument ist also, dass fehlerhafte Werte auftreten können, wenn>> dein Programm Fehler hat?>> Nein. Das habe ich nie gesagt. Ich habe das Gegenteil gesagt.
Es ist genau das, was dein Beispiel aussagt. Dein Programm enthält einen
Fehler, nämlich die Annahme, dass int_least16_t größer als 16 Bit ist.
Deshalb kommt auf Plattformen, wo das nicht gilt, ein falscher Wert
raus.
> Ich sagte, dass Fehler mit int_fast8_t (und Konsorten) leichter zu> produzieren sind und schwerer zu finden sind, als mit intX_t.
Das finde ich nicht.
> Dass das Programm fehlerhaft ist, ist unbestritten und Absicht.
Das ist mir schon klar.
> Es ging mir darum warum das Programm fehlerhaft ist.> Wir sind einer Meinung, nur du hast es noch nicht bemerkt.
Nein. Ich bin der Meinung, dass die fast- und least-Typen sinnvoll sind,
du offenbar nicht.
Rolf M. schrieb:> Dein Programm enthält einen> Fehler, nämlich die Annahme, dass int_least16_t größer als 16 Bit ist.
Du hast es immer noch nicht verstanden.
Es ging nicht um den Fehler ansich und auch nicht darum was genau der
Fehler ist.
Es ging darum, dass bestimmte Aktionen (casten) mit Verwendung der
Fast-Typen auf einmal plattformabhängig werden. Und dass das eventuell
schwieriger Im Griff zu behalten ist. Es ist schwieriger damit ein
korrektes Programm zu schreiben.
Jetzt verstanden?
Rolf M. schrieb:> Ich bin der Meinung, dass die fast- und least-Typen sinnvoll sind,
Dann begründe das doch mal.
Und nein, "alles wird magisch schneller" ist keine. Denn das ist nicht
der Fall.
Naja, explizites casten ist eine Aktion, die bei mir eigentlich recht
selten vorkommt. Und dann kommt auch kein klassischer "int" dabei vor,
sondern irgendein Typ fester Breite.
Warum sollte man einen int_fastX_t überhaupt auf einen Datentyp kleiner
x Bit casten wollen?
MaWin schrieb:> Es ging darum, dass bestimmte Aktionen (casten) mit Verwendung der> Fast-Typen auf einmal plattformabhängig werden. Und dass das eventuell> schwieriger Im Griff zu behalten ist. Es ist schwieriger damit ein> korrektes Programm zu schreiben.>> Jetzt verstanden?
Das ist schon klar, dass du das meintest. Nur trägt das Beispiel dazu
nicht sonderlich bei.
> Rolf M. schrieb:>> Ich bin der Meinung, dass die fast- und least-Typen sinnvoll sind,>> Dann begründe das doch mal.
Habe ich doch bereits. Es drückt genauer aus, was der Programmierer
will, was in der Regel eben nicht ein Typ mit exakt n Bits Größe ist,
sondern einer, der bestimmten Mindestanforderungen genügt.
> Und nein, "alles wird magisch schneller" ist keine. Denn das ist nicht> der Fall.
Es lässt dem Compiler die Wahl, welcher Typ an der Stelle am besten
geeignet ist.
MaWin schrieb:> Wenn jetzt eine Plattform sich entscheiden würde int_fast16_t> tatsächlich als int16_t zu implementieren, was ja erlaubt ist und z.B.> auf AVR8 wahrscheinlich der Fall sein dürfte, dann wäre die Ausgabe:
Hier bei mir (x64 Win10), ist int_fast16_t 16-Bit breit.
Die Fast Typen machen das Programm eher langsamer. Der Compiler muss
zwischen unterschiedlichen integer Typen konvertieren. Und wenn
int_fast16_t wirklich 64-Bit ist, dann braucht das unnötig Speicher
(Instructions sind länger und 4 facher Cache Bedarf). Einheitlich "int"
zu verwenden ist leichter lesbar und oft schneller. printf funktioniert
auch nicht mehr richtig ohne Cast Orgien...
1
#include <stdint.h>
2
int foo_int(int a, int b) { return a + b; }
3
int_fast16_t foo_fast16(int_fast16_t a, int_fast16_t b) { return a + b; }
4
int foo_mix(int a, int_fast16_t b) { return a + b; }
5
int64_t foo64(int64_t a, int64_t b) { return a + b; }
Liefert mit einem betagten MS cl compiler (der noch immer verwendet
wird, weil getestet):
Yalu X. schrieb:> Besser drei (für Three-Way-Merge). Bei einer minimalen horizontalen> Bildschirmauflösung von 1920 Pixel sind gerade etwa 3×80 Zeichen> möglich, ohne dass die Zeichen pixelig wirken. Für Programme in C,> Python und Haskell sind die 80 Zeichen auch völlig ausreichend, bei C++> wird es etwas grenzwertig.
Ich versuche hier auch, unter 80 Zeichen zu bleiben. Bei C++ werden es
manchmal auch etwas mehr. Damit kann ich mehrere Files nebeneinander
optisch vergleichen. Und manchmal wird das Zeugs ja auch noch
ausgedruckt abgelegt.
Rolf M. schrieb:>> Habe ich doch bereits. Es drückt genauer aus, was der Programmierer> will, was in der Regel eben nicht ein Typ mit exakt n Bits Größe ist,> sondern einer, der bestimmten Mindestanforderungen genügt.
Das hat man doch auch mit "int". Ist ja nichts anderes als ein integer
mit mindestens 16 Bit Breite laut Standard. Und am PC auf allen
relevanten Systemen 32 Bit.
Den einzigen integer Typ, den ich vermeide ist "long". Der ist auf
unterschiedlichen PC Systemen entweder 32 Bit (Windows), oder 64 Bit
(Linux).
Das macht nur Probleme.
> Das ist schon klar, dass du das meintest. Nur trägt das Beispiel dazu> nicht sonderlich bei.>
Eigentlich ist das Beispiel perfekt. Genau solche Fehler werden in der
Praxis andauernd passieren.
Rolf M. schrieb:> Es lässt dem Compiler die Wahl, welcher Typ an der Stelle am besten> geeignet ist.
Insbesondere compiliert etwas überhaupt noch auf einer Plattform, die
ein uint8_t nicht abbilden kann (weil sie bpsw. nur 32-Bit-Einheiten
überhaupt kennt). Wenn man außerdem Code bspw. zwischen ARM und AVR
portabel gestalten will, erzwingt uint8_t auf einem ARM oft genug
schlechteren Code (Maskierungen) als uint_fast8_t, während es auf dem
AVR keine Rolle spielt.
Aber uint_fast8_t in "ungarischer" Notation wird bestimmt ein lustiges
Geschreibsel. ;-)
PittyJ schrieb:> f_Counter = 1;>> Da weiss ich sofort, der Counter ist vom Type Float.
Eigentlich solltest du bei so etwas sofort wissen, dass grundlegend noch
ein Wurm in dem Programm ist. Da kräuseln sich einem die Fußnägel.
Jörg W. schrieb:> Aber uint_fast8_t in "ungarischer" Notation wird bestimmt ein lustiges> Geschreibsel. ;-)
cbFoo = cbBar + cbZoo;
Ist nicht so schwierig. Richtige Ungarische Notation kodiert nicht den
Typ,
sondern die Bedeutung (cb = Count of Bytes).
Und wenn dann da steht:
cbBoo = cchBar + cbZoo;
Dann weisst du sofort: Da ist ein Bug drinnen!
Ich kann keinen cb (Count of Bytes) mit einem cch (Count of Characters)
vermischen.
Udo K. schrieb:> Ist nicht so schwierig. Richtige Ungarische Notation kodiert nicht den> Typ,> sondern die Bedeutung (cb = Count of Bytes).
Warum muss ich bei einem Counter festlegen, dass ich Bytes zähle? Was
ist, wenn ich Objekte zähle? Was, wenn ich einen Zeiger auf das Objekt
"Speicherbereich" habe, aber ihm dann einen Zeiger auf ein Objekt
"Gerätetyp" zuweise? (Mal kurz zwei Beispiele aus AVRDUDE.) Was mache
ich für Bedeutungen, die sich Herr Simonyi nicht vorstellen konnte?
Rolf M. schrieb:> Es lässt dem Compiler die Wahl, welcher Typ an der Stelle am besten> geeignet ist.
Nur um der eventuellem Mißinterpretation vorzubeugen, daß der Compiler
da in Abhängigkeit des Kontextes Typen auswählen kann:
Es gibt der Implementierung auf einer Plattform die Möglichkeit, einen
passenden Typ festzulegen. Der Compiler hat keine Wahl bzw. weiß
überhaupt nichts davon. Der benutzt an allen Stellen für einen fast_int
den gleichen Typ.
Oliver
Udo K. schrieb:> cbBoo = cchBar + cbZoo;> Dann weisst du sofort: Da ist ein Bug drinnen!
In vernünftigen Sprachen regelt man das über das Typsystem und nicht
über die Variablennamen.
In C mit seinem primitiven Typsystem bleibt einem natürlich nichts
anderes übrig, als sich solche hässlichen Krücken auszudenken.
Jörg W. schrieb:> Warum muss ich bei einem Counter festlegen, dass ich Bytes zähle? Was> ist, wenn ich Objekte zähle? Was, wenn ich einen Zeiger auf das Objekt> "Speicherbereich" habe, aber ihm dann einen Zeiger auf ein Objekt> "Gerätetyp" zuweise? (Mal kurz zwei Beispiele aus AVRDUDE.) Was mache> ich für Bedeutungen, die sich Herr Simonyi nicht vorstellen konnte?
Musst du ja nicht. Die UN ist ja nur eine Möglichkeit mehr
Typ-Sicherheit einzubauen. Zähler und Index in Arrays sind meist
integer Typen, und daher kannst du die bunt durcheinanderwürfeln, und
der Compiler macht nicht mal eine Warnung. Mit der UN beseitigst du
dieses Typdefizit, und siehst sofort, ob eine Code-Zeile von den
Semantik her stimmen kann.
Üblicherweise stimmt was nicht, wenn du sowas siehst:
Udo K. schrieb:> Bestätigt doch, das er immer "int" intern verwendet...
Nein, wenn der Wertebereich von 32 bit nötig wäre (oder er es nicht
ermitteln kann), müsste er für den letzten Fall mehr als "int" nehmen
(das auf dem AVR ja nur 16 bits hat).
Wenn er ermitteln kann, was passend ist (hier: durch die Anzahl der
Array-Elemente vorgegeben), kann er entdprechend optimieren.
Jörg W. schrieb:> Wenn er ermitteln kann, was passend ist (hier: durch die Anzahl der> Array-Elemente vorgegeben), kann er entdprechend optimieren.
Ok, jetzt sehe ich es :-)
Das ist für Compiler heute kein Problem zum wegoptimieren.
Sonst müsste ja auch jeder Typ, der kleiner als ein int ist, erst mal
auf int konvertiert werden (Integer Promotion). Damit würden alle
Berechnungen mit kleineren Typen massiv benachteiligt werden.
Udo K. schrieb:> Das ist für Compiler heute kein Problem zum wegoptimieren.
Ja. Es widerspricht einfach nur obiger Behauptung, dass der real
verwendete Typ von vornherein irgendwie im Compiler festgezurrt wäre.
Jörg W. schrieb:> enn er ermitteln kann, was passend ist (hier: durch die Anzahl der> Array-Elemente vorgegeben), kann er entdprechend optimieren.
Ich habe das auf dem PC ausprobiert.
clang-cl -O1 macht da den kleinsten Code mit int, auch wenn es nur um
ein paar Bytes geht (int: 42 Bytes, int_fast16_t: 47 Bytes).
MS cl 2008 genauso, da ist der Unterschied 33 zu 39 Bytes.
MS cl 2022 macht keinen Unterschied: immer 34 oder 57 Bytes (-O1 / -O2).
Wenn ich bei clang-cl -O2 angebe, dann macht der loop unrolling -
What the fuck - Code size: int=133 Bytes, int_fast16_t=133 Bytes).
Jörg W. schrieb:>> Das ist für Compiler heute kein Problem zum wegoptimieren.>> Ja. Es widerspricht einfach nur obiger Behauptung, dass der real> verwendete Typ von vornherein irgendwie im Compiler festgezurrt wäre.
Der Compiler muss nur sicherstellen, dass sich der Code so verhält, als
würde er die Standard Regeln einhalten (inklusive integer Promotion).
Bei Konstanten ist das recht einfach, oder wenn alle Variablen denselben
Typ haben.
Jörg W. schrieb:> Oliver S. schrieb:>> Der benutzt an allen Stellen für einen fast_int den gleichen Typ.>> Das stimmt auch schon eine Weile nicht mehr.
Ja, aber das ist völlig unabhängig von den fast_/least-*-Typen.
Jörg W. schrieb:> Ja. Es widerspricht einfach nur obiger Behauptung, dass der real> verwendete Typ von vornherein irgendwie im Compiler festgezurrt wäre.
Da habe ich mich vielleicht mißverständlich ausgedrückt. Die
fast-/least-Typen werden als typedefs auf <unsigned>
char/short/int/long/... von der Implementierung festgezurrt.
Andere Typen kennt der Compiler gar nicht.
Oliver
Offensichtlich kennen zumindest manche Compiler durchaus andere Typen.
;-)
Aber ja, der Sinn ist natürlich, dass jede Implementierung für jede
ihrer Plattformen den passenden Typen damit abstrahieren kann.
Jörg W. schrieb:> Offensichtlich kennen zumindest manche Compiler durchaus andere Typen.> ;-)
Der gezeigte kennt überhaupt nur nur signed/unsigned int ;)
(Ok, mit ein paar nicht-standardkonformen Ergänzungen).
Oliver
Udo K. schrieb:> Rolf M. schrieb:>>>> Habe ich doch bereits. Es drückt genauer aus, was der Programmierer>> will, was in der Regel eben nicht ein Typ mit exakt n Bits Größe ist,>> sondern einer, der bestimmten Mindestanforderungen genügt.>> Das hat man doch auch mit "int".
Ja, aber int will MaWin ja auch nicht.
Jörg W. schrieb:> Das stimmt auch schon eine Weile nicht mehr.
Das ist eine ganz normale as-if Optimierung. Mit der Sprachsemantik auf
Typebene hat das absolut nichts zu tun.
Wenn der Compiler beweisen kann, dass er mit einem anderen Typ
effizienter zum gleichen Ergebnis kommen kann ohne das extern sichtbare
Verhalten zu ändern, dann darf er natürlich das intern machen.
Damit, wie Fast-Typen definiert sind, hat das gar nichts zu tun.
Ganz im Gegenteil. Die as-if Optimierungen sind der Hauptgrund dafür,
warum die Fast-Typen unnötig sind. Ein moderner Compiler kann viel
optimieren. Vor allem mit LTO.
Fast-Typen sind ein Relikt vergangener Zeiten.