Grundsatzfragen, Ungarische Notation



  • Ok bin ja noch ein rechter Neuling mit C++, hab zwar schon vorwissen in anderen Sprachen. Nun hab ich mich mal hingesetzt für meine eigenen Ürogramme wie ich es auch bei anderen Sprachen gemacht habe mir eine Art Grundfile gebastelt und natürlich auch eine Naming Convention.

    Nun meine Frage ob sowas in C++ sinvoll ist und ob mein Programm, speziell die Deklaration von main in meinem Programm stimmig mit meiner Naming Convention ist.

    /*
     * Project: Basefile
     * File: Basefile for console applicationsa
     */
    
    /*
     * Documentation:
     *
     * 1.1 Naming Convntion
     *
     *	bool			<-->	b
     *	char			<-->	ch
     *	string			<-->	sz
     *	unsigned short		<-->	us
     *	short			<-->	s
     *	unsigned integer	<-->	ui
     *	integer			<-->	i
     *	unsigned long		<-->	ul
     *	long			<-->	l
     *	float			<-->	f
     *	double			<-->	d
     *	long double		<-->	ld
     *	function		<-->	fn
     *	class			<-->	cl
     *	union			<-->	un
     *	struct			<-->	st
     *	enum			<-->	en
     *	pointer			<-->	p
     *	array			<-->	a
     *	member(class)		<-->	mb
     */
    
    /*
     * Defines
     */
    // main
    #define fnMain main
    // Pi
    #define PI 3.1415926535897932F
    // Euler
    #define E 2.7182818284590452F
    
    /*
     * Standard Includes
     */
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    
    /*
     * Header Includes
     */
    
    /*
     * Classes
     */
    
    /*
     * Globals
     */
    
    /*
     * Prototypes
     */
    
    /*
     * Functions
     */
    
    /*
     * Programm
     */
    int fnMain(int iArgc, char* pachArgv[])
    {
    	// TODO: Code
    
    	return 0;
    }
    

    Gruss Micha



  • Ne. Vor allem ist using namespace std; schnell wegzumachen.

    Prinzipiell ist alles, was du brauchst, in dein Programm zu machen. Eventuelle Module mit spezifischen Strukturen, Klassen und Funktionen kommen ja eventuell, also bei dem entsprechenden Projekt und nicht verallgemeinert.

    Wozu brauchst du das Makro für main() ?
    Und dann kannst du fnMain verkürzen:

    int fnMain()
    {
        //TO-DO Code
    }
    

    Naming Convention? Meinst du ungarische Notation, oder in diesem Fall (wurde selbst belehrt) Hungarian Notation? Ist eigentlich unnötig, erst in Klassen oder anderem kommt sie zum Einsatz. Meiner Meinung nach! Denn das ist Geschmackssache und völlig dir überlassen!

    Bitte auch kein Makro für PI und die Eulersche Zahl e. Lieber

    double const PI(/*...*/);
    

    Das 'F' am Ende ruiniert übrigens die Präzision, da es ja dann ein float-Literal wird (float kann nur max. 6 (Nachkomma)stellen repräsentieren, in diesem Fall 5).

    Und es ist auch unüblich, Globale Variablen zu verwenden. Das ist IMO C-Style.



  • Das makro ist eigendlich nur damit main halt fnMain heisst wies meine Naming Tabelle vorschreibt ist ja auch eigendlich eine Funktion.

    Andere Frage dazu warum int fnMain() und dann kein return 0; für das Ende?
    und warum die Übergabe von Parametern in der Konsole nicht direkt mit in mein Grundmodell einfügen?

    Wie gesagt das eigendlich nur eine Grundstruktur , die ich auch soweit von meinen anderen Sprachen her übernmmen und halt auf C++ abgeändert habe. Soll mir im grunde Einfach Grundsätzliche Tipparbeit sparen.
    ok die Pi und Euler in ne konstante zu packen macht Sinn werde das definitiv ändern und damit hab ich natürlich weil ich ja schreibfaul bin schon zwei Globale geschaffen.

    Gruss Micha.



  • Videonauth schrieb:

    Das makro ist eigendlich nur damit main halt fnMain heisst wies meine Naming Tabelle vorschreibt ist ja auch eigendlich eine Funktion.

    Versteh ich nicht. Wieso machst du nicht "mit dir selbst" den Kompromiss, einfach main() zu schreiben?

    Videonauth schrieb:

    Andere Frage dazu warum int fnMain() und dann kein return 0; für das Ende?
    und warum die Übergabe von Parametern in der Konsole nicht direkt mit in mein Grundmodell einfügen?

    Nur in main() (und auch nur da), kannst du das return DeineNummer; Weglassen. Dann wird "automatisch" 0 zurückgegeben.

    Der Standard schreibt vor, dass der Rückgabewert ein int sein muss. Sagt auch jeder Compiler: main must return int (GCC)

    Von main() gibt es zwei Varianten: eine, die Kommando-Zeilen Parameter ignoriert (benutze ich persönlich nur bei Qt, und nur weil ich es muss) und eine, die es tut. Im Intanet kannst du ja lesen, wie die Funktionsparameter von main(int, char**) gehandhabt werden 😉

    Nützlich sind diese Komandozeilen-Parameter, wenn du bspw. eine bestimmte File mit deinem Programm öffnen willst - deinen Filetype, z.B. *.sfw



  • Halt mich ruhig für blöd aber warum kein using namespace ?

    Nochmal wiederholend, es ist ein Grundkonstrukt was ich einfach kopiere und das lösche was ich nicht brauche.
    Deswegen auch die Frage ob die notation für z.b. Argv[] stimmt wenn ich das richtig sehe ist das ein pointer array für chars !?

    Gruss Micha


  • Mod

    Videonauth schrieb:

    Halt mich ruhig für blöd aber warum kein using namespace ?

    Weil dann jedes Modul, welches deinen Header einbindet, atuomatisch ein using namespace hat, wodurch der ganze Sinn von Namespaces abhanden geht. Daher mach es nicht in Header.



  • So Hab die Defines für euler und Pi nun rausgenommen und das genuzt.

    /*
     * Globals
     */
    // Pi
    const long double PI = 3.1415926535897932;
    // Euler
    const long double EUL = 2.7182818284590452;
    

    Frage dazu ist eigendlich nur, wie viele nachkommastellen kann mein long double haben? Derzeit hab ich da 16 aber will dann schon die maximal mögliche Genauigkeit ausschöpfen.

    Gruss Micha



  • Videonauth schrieb:

    /*
     * Project: Basefile
     * File: Basefile for console applicationsa
     */
    
    /*
     * Documentation:
     *
     * 1.1 Naming Convntion
     *
     *	bool			<-->	b
     *	char			<-->	ch
     *	string			<-->	sz
     *	unsigned short		<-->	us
     *	short			<-->	s
     *	unsigned integer	<-->	ui
     *	integer			<-->	i
     *	unsigned long		<-->	ul
     *	long			<-->	l
     *	float			<-->	f
     *	double			<-->	d
     *	long double		<-->	ld
     *	function		<-->	fn
     *	class			<-->	cl
     *	union			<-->	un
     *	struct			<-->	st
     *	enum			<-->	en
     *	pointer			<-->	p
     *	array			<-->	a
     *	member(class)		<-->	mb
     */
    

    Das wird aber hässlich.



  • 100% schrieb:

    Videonauth schrieb:

    /*
     * Project: Basefile
     * File: Basefile for console applicationsa
     */
    .
    .
    .
    .
    

    Das wird aber hässlich.

    Das ist muss ich zugeben wenig konstruktiv!

    Gruss Micha



  • Videonauth schrieb:

    Das ist muss ich zugeben wenig konstruktiv!

    Das muss ich auch zugeben.
    Allerdings: Die "Hungarian Notation" ist im gesamten modernen C++ Umfeld ziemlich ungern gesehen. Man kann es halbherzig versuchen, aber dann bringt es nichts. Und man kann es wirklich bis in jede Ecke durchziehen - dann wird das System aber sehr komplex und Namen unnötig lang und unlesbar. Daher verzichte am besten komplett darauf. (Wie auch der Standard und so ziemlich jedes Buch und Coding Styles das machen.)

    Edit:
    Und zu den Kommentaren mit File, Prototypes etc.: Auch sparen. Wenn das alles so undurchsichtig wird, dass solche Kommentare helfen, dann ist das ein klares Zeichen dafür, dass du mal aufräumen, sprich den Kram in mehrere Dateien/Module aufteilen solltest. (Auch wenn sich nicht gerade alle open source Projekte daran halten. 🤡 )



  • OK, dann werd ich das nochmal überdenken.

    Gruss Micha



  • Wieviel Stellen (merke: nicht Nackkommastellen!) eine Fließkommazahl hat, kannst du so feststellen:

    size_t const max_precision_double = std::numeric_limits<double>::digits10;
    

    Für diese Methode musst du den <limits> -Header einbinden.
    OMC ist max_precision_double 18.

    Bspw. hast du eine Zahl die mit 52. Anfängt - die also zwischen 52 und 53 liegt - so kannst du sie bis auf die 16te Nachkommastelle genau in einem [/c]double[c] speichern.



  • Überleg dir welchen Mehrwert UN überhaupt bringt.
    Man sieht, wenn man die genaue Definition der Bezeichner kennt, sofort welchen Typ eine Variable hat. Das kann man Heute auch mit einer modernen IDE mit einem Maus-Hover auch herausfinden und hat dann ganz sicher den Typen und nicht möglicherweise eine nicht refaktorisierten Namen. Meistens geht aber der Typ einer Variable auch aus dem Kontext hervor.



  • Ah, ungarische Notation mal wieder. Das Thema kommt alle Nase lang mal wieder auf und ist mehr oder weniger heiß umstritten, aber es scheint eine Art Konsens zu geben, dass sie in der von dir beschriebenen Form (mit Typbezeichnern im Namen) unsinnig ist.

    Das grundsätzliche Problem damit ist, dass dir erstens der Typ im Namen nicht so richtig viel bringt und man sich zweitens erfahrungsgemäß nicht die Mühe macht, den Bezeichner überall zu ändern, wenn man man den Typen ändert. Irgendwann hast du doch

    double nPreis;
    

    irgendwo stehen.

    Etwas anderes ist es beim sog. "Applications Hungarian", bei der nicht der konkrete Datentyp, sondern ihr Zweck beschrieben wird. Ein praktisches Beispiel wäre die Unterscheidung zwischen unbereinigten und bereinigten Strings, etwa

    std::string usInput = get_stuff_from_network_socket(); // us = unsanitized
    std::string sInput  = sanitize(usInput);
    

    Auf die Art könne man später schneller sehen, dass bei

    do_sql(usInput);
    

    unbereinigter Input an die Datenbank durchgereicht wird, was tunlichst vermieden werden sollte.

    Dem kann man so oder so gegenüberstehen. Es ist natürlich sinnvoll, den Zweck einer Variable in ihrem Namen festzuhalten; ob man das jetzt in Prä- oder Postfixform und in CamelCase, javaCase oder underscore_separated macht, ist eher nebensächlich.

    Besser noch ist es, solche Dinge gleich im Typsystem zu verankern, im konkreten Beispiel etwa zwei Klassen unsanitized_string und sanitized_string zu haben, so dass der Compiler sich ggf. beschweren oder die Bereinigung automatisch bei der Umwandlung passieren kann. Das ist aber schon für Fortgeschrittene.



  • Schade das es hier keine Danke Buttons gibt aber ich muss mich mal bei dir bedanken seldon und natürlich auch bei den anderen Postern. ich denke ich werde es hier herauslassen obwohl ich dieses System eigendlich gewohnt bin. Am ende bleibt im compilierten sowiso nichts mehr davon übrig.

    Gruss Micha



  • Videonauth schrieb:

    Nun meine Frage ob sowas in C++ sinvoll ist

    Nicht wirklich.



  • @ NEXUS

    Dein Link Wäre einen Sticky wert. Das hätte meine Frage erst garnicht aufkommen lassen.

    Gruss Micha



  • Videonauth schrieb:

    /*
     * Globals
     */
    // Pi
    const long double PI = 3.1415926535897932;
    // Euler
    const long double EUL = 2.7182818284590452;
    

    Frage dazu ist eigendlich nur, wie viele nachkommastellen kann mein long double haben? Derzeit hab ich da 16 aber will dann schon die maximal mögliche Genauigkeit ausschöpfen.

    Nachkommastellen werden nicht definiert aber signifikante Dezimalstellen insgesamt als DBL_DIG bzw. LDBL_DIG in <cfloat>.

    const long double PI = 3.1415926535897932;
    

    ist auch suboptimal gelöst, da du die evtl. höhere Signifikanz von long double gegenüber double deines Compilers durch Weglassen des long-double-Typspezifizierers nicht ausnutzt.
    Besser also

    const long double PI = 3.1415926535897932L;
    


  • Wutz schrieb:

    Videonauth schrieb:

    /*
     * Globals
     */
    // Pi
    const long double PI = 3.1415926535897932;
    // Euler
    const long double EUL = 2.7182818284590452;
    

    Frage dazu ist eigendlich nur, wie viele nachkommastellen kann mein long double haben? Derzeit hab ich da 16 aber will dann schon die maximal mögliche Genauigkeit ausschöpfen.

    Nachkommastellen werden nicht definiert aber signifikante Dezimalstellen insgesamt als DBL_DIG bzw. LDBL_DIG in <cfloat>.

    const long double PI = 3.1415926535897932;
    

    ist auch suboptimal gelöst, da du die evtl. höhere Signifikanz von long double gegenüber double deines Compilers durch Weglassen des long-double-Typspezifizierers nicht ausnutzt.
    Besser also

    const long double PI = 3.1415926535897932L;
    

    Soweit ich weiß, erkennt der Compiler automatisch die entsprechenden Typen der Literale, wenn es um Größen geht. Aber Danke!



  • Hacker schrieb:

    Soweit ich weiß, [...]

    Eben. Es ist nicht so wie du weisst.

    Der Compiler erkennt zwar floats und doubles anhand der Länge, aber bei long double hört der Spass auf.

    Bei Fullquotes übrigens auf.


Anmelden zum Antworten