Ungarische Notation veraltet
-
Lasst die Variablen doch jeden seine so nennen, wie er am besten damit zurecht kommt. Kritisch wird es erst, wenn man mit mehreren Personen an einem Projekt arbeitet - dann sollte man sich auf eine Schreibweise einigen.
Ich habe auch total chaotisch angefangen mit den Bezeichnungen, aber mit jedem Projekt habe ich meine Schreibweise verbessert, so dass ich jedes Mal besser damit zurecht kam - und darauf kommt es eben erstmal an.
Inzwischen sieht das so aus:
Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.
Präfixe für Variablenbezeichner:
b: bool
c: char/char*
h: Funktionszeiger (Callbacks)
o: Objekte (Typ wird aus dem Namen klar, ansonsten wäre auch der Präfix zu lang)
s: sint8/sint16/sint32/sint64 (ganzzahlig, mit Vorzeichen)
u: uint8/uint16/uint32/uint64 (ganzzahlig, ohne Vorzeichen)
v: void*
w: wchar_t/wchar_t*Typbezeichner bestehen aus einem Präfix (Großbuchstaben) für die Art des Typs, gefolgt vom Namen.
Präfixe für Typbezeichner:
S: struct (SBlubb, SBla, SWasAuchImmer)
C: class (CBlubb, CBla, CWasAuchImmer)
T: für spezielle Typedefs (TSize, TOffset, TPosition - jeweils Systemabhängig, ähnlich wie size_t)Statische Variablen haben vor dem Präfix noch ein '_' (wobei ich noch nicht weiß, ob das Probleme verursachen kann. Eine bessere Lösung habe ich hier noch nicht.).
Auf Membervariablen der aktuellen Klasse wird explizit per 'this->' zugegriffen.
[edit]Inzwischen habe ich mir auch vorgeschrieben, Bezeichner nicht mehr abzukürzen (uPosition statt uPos, sOffset statt sOff, uLength statt uLen, etc.), seien die Bezeichner auch noch so lang. Die Abkürzungen waren vor IntelliSense schneller zu schreiben, aber dafür war der Code schwerer zu lesen.[/edit]
Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.
-
Neku schrieb:
Lasst die Variablen doch jeden seine so nennen, wie er am besten damit zurecht kommt. Kritisch wird es erst, wenn man mit mehreren Personen an einem Projekt arbeitet - dann sollte man sich auf eine Schreibweise einigen.
Ich habe auch total chaotisch angefangen mit den Bezeichnungen, aber mit jedem Projekt habe ich meine Schreibweise verbessert, so dass ich jedes Mal besser damit zurecht kam - und darauf kommt es eben erstmal an.
Inzwischen sieht das so aus:
Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.
Präfixe für Variablenbezeichner:
b: bool
c: char/char*
h: Funktionszeiger (Callbacks)
o: Objekte (Typ wird aus dem Namen klar, ansonsten wäre auch der Präfix zu lang)
s: sint8/sint16/sint32/sint64 (ganzzahlig, mit Vorzeichen)
u: uint8/uint16/uint32/uint64 (ganzzahlig, ohne Vorzeichen)
v: void*
w: wchar_t/wchar_t*Typbezeichner bestehen aus einem Präfix (Großbuchstaben) für die Art des Typs, gefolgt vom Namen.
Präfixe für Typbezeichner:
S: struct (SBlubb, SBla, SWasAuchImmer)
C: class (CBlubb, CBla, CWasAuchImmer)
T: für spezielle Typedefs (TSize, TOffset, TPosition - jeweils Systemabhängig, ähnlich wie size_t)Statische Variablen haben vor dem Präfix noch ein '_' (wobei ich noch nicht weiß, ob das Probleme verursachen kann. Eine bessere Lösung habe ich hier noch nicht.).
Auf Membervariablen der aktuellen Klasse wird explizit per 'this->' zugegriffen.
[edit]Inzwischen habe ich mir auch vorgeschrieben, Bezeichner nicht mehr abzukürzen (uPosition statt uPos, sOffset statt sOff, uLength statt uLen, etc.), seien die Bezeichner auch noch so lang. Die Abkürzungen waren vor IntelliSense schneller zu schreiben, aber dafür war der Code schwerer zu lesen.[/edit]
Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.
Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...
-
Ein ganz kurzer schrieb:
Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...
Ich gebe zu, die Beispiele waren nicht die besten
-
Neku schrieb:
Ein ganz kurzer schrieb:
Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...
Ich gebe zu, die Beispiele waren nicht die besten
Na dann ist ja gut.
-
Neku schrieb:
Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.
Was bringt es dir dann? du bist am ende genauso klug wie jemand der keine prefixe verwendet...
schlimmer noch:
cFoo
soll ein zeiger sein? aua aua aua.Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.
das ist imho die falsche einstellung...
PS:
naja, schon komisch was manche leute fuer vorlieben haben... da lob ich mir ehrlich gesagt typenlose sprachen, da kommen die leute nicht auf so komische ideen...
oder javafuer all seine fehler, wenigstens kommt dort keiner auf die idee ungarisch zu verwenden... immer diese C altlasten
-
Neku schrieb:
c: char/char*
v: void*
w: wchar_t/wchar_t*zwischen pointern und nicht-pointern machste keinen unterschied? das ist schlecht.
-
Das unterscheidet halt die C+- und von den C++-Programmierern..
-
net schrieb:
Neku schrieb:
c: char/char*
v: void*
w: wchar_t/wchar_t*zwischen pointern und nicht-pointern machste keinen unterschied? das ist schlecht.
Bei void sollte der Fall klar sein
char und wchar_t werden nur sehr sehr selten benutzt, da ich für Strings idR eine Stringklasse verwende. Sollten dennoch char oder wchar_t auftauchen, so wird aus dem Variablen klar, was gemeint ist (z.B. wCharacter).@Shade Of Mine: Bei typenlosen Sprachen dürfte es sogar noch wichtiger sein, Präfixe abhängig des Typs zu verwenden, denn dort weist einen der Compiler nicht auf Probleme hin. Angenommen du verwendest irgendwo eine Variable als String und anderswo aus versehen als bool in einer Bedingung (noch besser in PHP: ein Array als Boolean :))
Und erklär doch mal, warum das "die falsche einstellung" ist, wenn ich der einzige bin, der den Code je zu sehen bekommt.
Von C kommt das bei mir übrigens nicht. Ich habe direkt mit C++ angefangen und auch erst Variablennamen ohne Typ-Präfix verwendet. Das endete generell im Chaos und so habe ich mir mit der Zeit eine hilfreiche Bezeichnerregelung geschaffen.Shade Of Mine schrieb:
cFoo
soll ein zeiger sein? aua aua aua.Da ich nur in schätzungsweise 0.1% meines Quellcodes Variablen vom Typ char habe liegt es nahe, einfach c für char* zu verwenden.
-
Neku schrieb:
Bei typenlosen Sprachen dürfte es sogar noch wichtiger sein, Präfixe abhängig des Typs zu verwenden, denn dort weist einen der Compiler nicht auf Probleme hin.
Bei typenlosen Sprachen kann eine Variable auch mal den Typ wechseln. Was hilft dir dann deine Ungarische Notation!?
Greetz, Swordfish
-
Ich bin auch von der Ungarischen Notation abgekommen.
A) Sind meine Funktionen überschaubar kurz
Nutze ich sprechende Variablennamen: Also z.B. AngestellterName statt m_wspzAname
C) Hab ich keine Probleme wenn sich der Typ meiner Variablen ändert. Gut mit passenden Refactoringmthoden kann ich schnell alle m_wspzAname in m_wspAname umändern - aber ich denke ihr wisst was ich meine.
-
Ich finde die ungarische Notation absolut nicht intuitiv.
Ich weiß noch ganz genau, wie ich damals mit DirectX / WinApi angefangen habe, die ganzen Abkürzungen waren total nichtssagend und der Sinn blieb mir verschlossen.Hilft also nur, wenn man diese komische Notation bereits beherrscht.
btw. C vor Klassennamen ist hässlich :p
-
Na was ist denn nun der Unterschied zwischen lptstrAngestellterName und AngestellterName? Der Mehrwert an nützlichen Infos hält sich doch arg in Grenzen ( = 0). Und ob eine Nullterminierte Zeichenkette erwartet wird kann man doch eigentlich auch am Aufbau der Funktion erkennen.
void Foo::SetzeName(char* AngestellterName) //kann ja nur Nullterminierte Zeichenkette erwarten, wie sollte man sonst das Ende der Zeichenkette erkennen? { } void Foo::SetzeName(char* AngestellterName, int Laenge) //Länge der Zeichenkette mit übergeben -> Nullterminierung nicht unbedingt notwendig { }
Vieleicht irre ich mich auch und die Logik ,die ich hinter dem obigen Code sehe, ist total falsch. Bitte flame't mich dann zu.
EDIT: Rechtschreibung++
-
Die ungarische Notation kannst du meines Wissens komplett vergessen.
-
wisser schrieb:
Die ungarische Notation kannst du meines Wissens komplett vergessen.
Das sehe ich auch so.
-
hehejo schrieb:
Ich bin auch von der Ungarischen Notation abgekommen.
A) Sind meine Funktionen überschaubar kurz
Nutze ich sprechende Variablennamen: Also z.B. AngestellterName statt m_wspzAname
C) Hab ich keine Probleme wenn sich der Typ meiner Variablen ändert. Gut mit passenden Refactoringmthoden kann ich schnell alle m_wspzAname in m_wspAname umändern - aber ich denke ihr wisst was ich meine.zu A): Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch :))
zu B): wie du unter A) siehst, funktioniert das auch mit Variablen, welche einen kleinen Typen-Präfix haben.
zu C): An sich hast du recht, man muss es überall ersetzen. Andererseits muss man in den meisten Fällen ohnehin den Code ändern, damit dieser mit dem neuen Typ funktioniert. Bei deinem Beispiel '_wspzAname' nach 'm_wspAname' gehe ich mal davon aus, dass du ein wchar_t* von einem nullterminierten String in einen nicht-nullterminierten String änderst. In dem Fall würden sämtliche Funktionen, welche die Nullterminierung erfordern, Probleme verursachen.
Ansonsten bieten die meisten IDEs inzwischen gute Suchen&Ersetzen-Funktionen an.Chris++ schrieb:
Na was ist denn nun der Unterschied zwischen lptstrAngestellterName und AngestellterName? Der Mehrwert an nützlichen Infos hält sich doch arg in Grenzen ( = 0). Und ob eine Nullterminierte Zeichenkette erwartet wird kann man doch eigentlich auch am Aufbau der Funktion erkennen.
void Foo::SetzeName(char* AngestellterName) //kann ja nur Nullterminierte Zeichenkette erwarten, wie sollte man sonst das Ende der Zeichenkette erkennen? { } void Foo::SetzeName(char* AngestellterName, int Laenge) //Länge der Zeichenkette mit übergeben -> Nullterminierung nicht unbedingt notwendig { }
Vieleicht irre ich mich auch und die Logik ,die ich hinter dem obigen Code sehe, ist total falsch. Bitte flame't mich dann zu.
EDIT: Rechtschreibung++
Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.
-
Suchen und Ersetzen widerlegt jeglichen Sinn der Typkodierung in den Variablennamen, aber nur so am Rande.
Leute die den Typ in den Variablennamen einkodieren haben den Sinn von OOP oder generischer Programmierung nicht verstanden.
-
Das Thema interessiert mich schon lange und anscheinend sind hier viele Profis unterwegs. Folgendes Beispiel:
CString CStringName; BSTR BSTRName; MyCOMObject->get_Name(&BSTRName); CStringName = (LPCTSTR)BSTRName;
Wie markiert ihr gleiche Variablen mit unterschiedlichen Typen? Vor allem bei String, da es dort unzählige Varianten gibt.
-
CString getName() { BSTR name; MyCOMObject->get_Name(&name); return (LPCTSTR)name; }
-
Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.
Wo ist da der Unterschied ?
std::string AngestellerNameA = "Mayer"; char* AngestellerNameB = "Mayer"; wchar_t* AngestellerNameC = "Mayer";
Wo ist da ein Unterschied ?
Anderes Beispiel:int counterA = 0; long counterB = 0; float counterC = 0; ... counterA++; counterC++; counterD++;
Wo ist da ein Unterschied ?
Beispiel mit Klassen/Struct:
struct LiedA { std::string album; std::string titel; LiedA(std::string album, std::string titel) { this->album = album; this->titel = titel; } std::string getAlbum() { return album; } std::string getTitel() { return titel; } } class LiedB { public: std::string album; std::string titel; LiedB(std::string album, std::string titel) { this->album = album; this->titel = titel; } std::string getAlbum() { return album; } std::string getTitel() { return titel; } }
Wozu muss ich jetzt wissen ob Lied eine Klasse oder Struktur ist ?
Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch )
Jetzt muss ich also mir nicht nur den Namen der Variable sondern auch ihren Type merken?
Statt einzutippen "coun" und die Autovervollständigung macht mir counterFürAlles,
muss ich
i_coun -> hmm da kommt nix
s_coun -> hmm da kommt auch nix
w_coun -> hmm da kommt wieder nix, welchen Type habe ich den gemacht ??
u_coun -> ahh endlich -> u_counterFürAllesWas ich damit sagen will: Ich will den Typen überhaupt nicht wissen. Wenn etwas falsch ist, dann meldet der Compiler! ein Fehler oder eine Warnung. Dafür ist der Compiler da. In C++ gibt es nicht umsonst Operatorüberladung damit Klassen sich wie Buildin-Typen anfühlen. Das ist eben einer der Vorteile von OOP-Sprachen wie C++, Java, C#, Ruby, usw.
-
DEvent schrieb:
int counterA = 0; long counterB = 0; float counterC = 0; ... counterA++; counterC++; counterD++;
Wo ist da ein Unterschied ?
Das ist einfach:
[cpp]
int counterA = 0;
long counterB = 0;
float counterC = 0;...
counterA++;
counterC++;
counterD++;[/cpp]SCNR
@electron, wenn du das nicht öfter machen musst, dann könnte man eine Funktion dafür auch weglassen und die Variablen einfach passend bennenen:
CString name; BSTR tempName; MyCOMObject->get_Name(&tempName); name = (LPCTSTR)tempName;
Jetzt ist sofort ersichtlich, dass BSTR nur dazu verwendet wird um den Namen zwischenzuspeichern und nach diesem Codeblock keine weitere Rolle mehr spielt.
Aber eine Funktion wie von :o vorgeschlagen ist natürlich zu Bevorzugen, wenn du das des öfteren machst.