Hallo Besucher, der Thread wurde 446k mal aufgerufen und enthält 2290 Antworten

letzter Beitrag von Claus am

Heute so gecodet...

  • DP64 ich glaube Du verwechselst hier was. Es geht nicht um das ++ oder --, es geht um das Konstrukt welches daybyter geschrieben hat, welches a=b++ lautete.


    Und nein, Python hat kein ++ aber es gibt +=

    Genau das habe ich gemeint!

  • Man kann auch so coden (aus dem IOCCC 2019)


  • Der MISRA C Standard schreibt z.B. folgendes vor:

    MISRA ist in weiten Teilen ziemlicher Mist (dürfte aber das Ziel, dass auch Programmierer mit "durchschnittlichen" C-Kenntnissen sicher coden, trotzdem erreichen). Die zitierte Regel ergibt Sinn, ist aber unsinnig formuliert. Eine "order of evaluation" ist in C gar nicht definiert, lässt sich aber aus der Grammatik ableiten. Nur hilft die hier nichts, die sagt dir am Ende nur, welche Operatoren stärker binden. Der Beispielcode aus dieser Regel:

    x = b[i] + i++;

    ist schlicht undefined behavior. Das liegt daran, dass i hier zweimal evaluiert wird, ohne sequence point dazwischen, wobei aber i++ einen Seiteneffekt hat. Die beiden Evaluationen sind "unsequenced", damit könnte der Seiteneffekt passieren, bevor b[i] gelesen wird, oder auch danach. "Order of evaluation" hilft hier nichts, selbst etwas wie

    x = b[i] * (a + i++);

    wäre UB, obwohl hier (a + i++) vor der Multiplikation berechnet werden muss. Trotzdem ist es unsequenced und damit auch undefiniert, auf welches Element von b zugegriffen wird. Es geht hier lediglich um "sequence points", die definieren, an welchen Stellen Seiteneffekte abgeschlossen sein müssen.


    Jedes ; in C ist ein sequence point, es gibt allerdings noch ein paar andere :)


    All das hat nichts mit Code wie a = b++; zu tun -- das ist völlig ok und wohldefiniert.


    edit: im Text der Regel ist das meiste tatsächlich korrekt, leider ist auch hier die Rede von "order of evaluation", dabei geht es nicht ums evaluieren sondern darum, wann ein Seiteneffekt passiert ...

  • All das hat nichts mit Code wie a = b++; zu tun -- das ist völlig ok und wohldefiniert.

    Trotzdem sollte man so etwas vermeiden.


    Edit: Genauso wie den Nicht Operator (!) oder den ternären Operator (Ausdruck) ? x : y;

  • All das hat nichts mit Code wie a = b++; zu tun -- das ist völlig ok und wohldefiniert.

    Trotzdem sollte man so etwas vermeiden.


    Edit: Genauso wie den Nicht Operator (!) oder den ternären Operator (Ausdruck) ? x : y;

    Jetzt wirds glaube ich sehr subjektiv. Gerade den ternären Operator verwende ich in bestimmten Situationen bevorzugt, anstatt unnötige if/else-Konstrukte zu schreiben. Eine objektive Begründung, warum man das vermeiden sollte fehlt weiterhin.

  • All das hat nichts mit Code wie a = b++; zu tun -- das ist völlig ok und wohldefiniert.

    Trotzdem sollte man so etwas vermeiden.


    Edit: Genauso wie den Nicht Operator (!) oder den ternären Operator (Ausdruck) ? x : y;

    Das halte ich in dieser Allgemeinheit für Unsinn. Ternäre Ausdrücke werden leicht unleserlich, wenn das passiert weiß man, dass man es falsch gemacht hat. In einer einfachen Form sind sie aber sogar viel besser lesbar als unnötiges if-else-geschachtel.


    Was gegen ! sprechen soll erschließt sich mir so absolut nicht. Gedacht ist der Operator für simple Anwendungen wie


    Code
    1. int has_foo = 0;
    2. ...
    3. if (! has_foo)
    4. {
    5.     ...
    6. }


    Natürlich wäre eine Anwendung wie if (!(a < b)) kompletter Unsinn und der Produzent dieses Codes gehört geteert und gefedert.


    Übrigens gibt es keine kompaktere Schreibweise um ein beliebiges int als "bool" (0 oder 1) zu normalisieren als !!a, durchaus ein gängiges Idiom.

  • Dein Beispiel wäre leserlicher (ja das ist natürlich auch Gewohnheit), wenn man:

    if (has_foo == 0)  schreiben würde.

    Gegen den ! Operator spricht, dass er oft als "Abkürzung" verwendet wird. Gegen:

    if (a != b)  habe ich nichts einzuwenden.


    Guter Stil ist, wenn man Variablen nach Datentyp behandelt:

    while (i < 10)

    if (a == true) 

    if (b <= LIMIT)

    while (exit == false)


    Übrigens gibt es keine kompaktere Schreibweise um ein beliebiges int als "bool" (0 oder 1) zu normalisieren als !!a, durchaus ein gängiges Idiom.

    Mischen von Datentypen, pfui!

  • Gegen den ! Operator spricht, dass er oft als "Abkürzung" verwendet wird.

    Kannst Du dazu auch ein Beispiel geben, was Du als "Abkürzung" bezeichnest?

    Ich finde bspw. es spricht nichts dagegen, es bei einem boolschen Datentypen wie folgt zu verwenden:

    Code
    1. if ( !bHasProperties )
    2.     return;

    Aber ob Du das meinst, weiß ich natürlich nicht.

  • Hmm jetzt wirds glaub echt sehr subjektiv :D


    Also ich finde ein "while (! exit)" deutlich logischer und schneller lesbar/erkennbar als ein "while (exit == false)", meist wird ja eher von letzterer Form abgeraten.

  • while (exit == false)

    Ähm bitte was? Am besten auch noch if (exit == true)? Das halte ich für mit den schlimmsten Murks, den man schreiben kann. if erwartet einen Ausdruck mit Wahrheitswert ... wenn ich schon einen Wahrheitswert habe, den mit einem anderen Wahrheitswert zu vergleichen um einen Wahrheitswert zu bekommen ... äh ja ... :o

    Übrigens gibt es keine kompaktere Schreibweise um ein beliebiges int als "bool" (0 oder 1) zu normalisieren als !!a, durchaus ein gängiges Idiom.

    Mischen von Datentypen, pfui!

    bool ist kein Datentyp in C -- ein "bool" ist traditionell ein int, "gemischt" wird hier also gar nichts. Seit C99 gibt es bool als (optional nutzbares) Makro für den neuen Typ _Bool, der ebenfalls ein Integertyp mit mindestens 8 bit ist, allerdings muss _Bool tatsächlich nicht mehr als 0 oder 1 darstellen können, der Rest dürfen theoretisch "trap representations" sein. Außerdem gibt's dazu die Makros true und false, kaum überraschend definiert als 1 und 0. Dank "integer promotion" Regeln wird jeder integer-Typ für Berechnungen ohnehin mindestens auf die Größe eines int konvertiert -- !!a wäre also immer noch völlig korrekt, wenn man für a tatsächlich den Typ _Bool nimmt. Für int sowieso.

  • > ...- Kein Verändern des Programms on the fly beim Durchsteppen.

    - In Grenzen möglich, wenn man keine Strukturen verändert. Aber C# ist ein Compiler, kein Interpreter.

    VB6 kompiliert P-Code oder wahlweise native Code. Dei Beschränkungen bei Änderungen im Laufenden Programm sprechen imho auch dafür, dass VB6 einzelne Unterprogramme oder Module "mal kurz" neu kompilieren kann.
    In .Core/vsCode kann man zwar was eintippen, aber es wird nicht berücksichtigt und bringt in der Regel auch noch die Anzeige des nächsten Befehls durcheinander. Im Grunde starte ich bei jeder nötigen Änderung komplett neu - und das dauert!


    Zitat

    C# ist wie gesagt kein Basic-Interpreter. Die von dir aufgeführten Probleme haben nur Basic- und Python-Programmierer, wenn sie zu C# wechseln. C- und Java-Programmierer eher nicht.

    Naja, falsche ; oder = und == sind Klassiker, die auch Basic-Programmierer kennen.

    Zitat

    Fehlende Unterscheidung von Groß/Kleinschreibung nimmt einem unglaublich viele Informationen, wenn man entsprechenden Konventionen verwendet. Zum Beispiel die Unterscheidung zwischen Klassen- und Instanzennamen.

    Ist das jetzt nicht ein Zirkelbezug? Groß/Klein ist nützlich bei Konventionen, die man ohne gar nicht hätte.
    In VB war bei uns Konvention, Instanzen mit einem Kürzel des Klassen-Namens anfangen zu lassen, wie FmMain für Formulare. So hab ich es jedenfalls damals von meinen Kollegen übernommen, die von C auf Atari und DOS gekommen sind.

    Zitat

    Gibt es ausser Basic noch eine Sprache, wo die Groß/Kleinschreibung egal ist?

    Html, SQL fallen mir da ein.
    Wobei ich fast schwören möchte, dass in SQL sogar String-Vergleiche nicht Case-sensitiv sind, aber da kann ich mich jetzt auch täuschen.
    JSon ist eigentlich Case-sensitive, aber beim Umwandeln in Objekte scheint das bei Keys allgemein nicht so eng gesehen zu werden. Das klappt einfach, quer von SAP rüber nach .Net. Das erspart auch Schmerzen, wenn man nicht nach der genauen Schreibweise von "Auto" fragen muss.

    ----------------

    A propos:

    - Dieses Yoda-SQL, das in C# eingebaut ist: Schön nicht es ist.

    - "Für Primärschlüssel nimmt man heute GUIDs, auch wegen Replikation und so". Und dann haut EF da nen clustered Index drauf.
    ----------------

    Manche Kollegen mögen ein IF BOOL = FALSE THEN oder gar ein ... BOOL = TRUE THEN...
    Erstaunlicherweise scheint ein BOOL = (AY>5) auch schwierig zu sein, das wird gerne durch IF ersetzt.

  • In VB war bei uns Konvention, Instanzen mit einem Kürzel des Klassen-Namens anfangen zu lassen, wie FmMain für Formulare. So hab ich es jedenfalls damals von meinen Kollegen übernommen, die von C auf Atari und DOS gekommen sind.

    Das ist übrigens auch eine Konvention von vorgestern: https://de.wikipedia.org/wiki/Ungarische_Notation#Kritik

    Dieses Yoda-SQL, das in C# eingebaut ist: Schön nicht es ist.

    Du sprichst vermutlich von LINQ ... das ist eben KEIN SQL -- wer sagt denn, dass es nur eine "query language" geben darf? ;) Ich persönlich mag übrigens beides nicht (und bevorzuge es, "LINQ-APIs" direkt mit lambdas zu verwenden).

    "Für Primärschlüssel nimmt man heute GUIDs, auch wegen Replikation und so". Und dann haut EF da nen clustered Index drauf.

    Da solltest du mal erklären, was daran als default schlecht sein soll. Aber abgesehen davon: EF halte ich auch nicht für der Weisheit letzter Schluss. Wir halten davon bewusst Abstand.

  • Code
    1. for ( x=0; x<y; x++ )

    wird denke ich mal häufig verwendet...

    Sollte es in Python eigentlich nicht, gilt auch als nicht idiomatisch.

    Üblicherweise sieht das eher so aus:

    Code
    1. for x in range(y):

    Das ist aber meist eine Krücke, um in der Schleife mit mylist[x] auf Listenelemente zuzugreifen. Dann eher:

    Code
    1. for item in mylist:

    Wenn der Index des aktuellen Elements dringend benötigt wird:


    Code
    1. for index, item in enumerate(mylist):
  • Das ist übrigens auch eine Konvention von vorgestern: https://de.wikipedia.org/wiki/Ungarische_Notation#Kritik

    Wenn man es mit der Notation übertreibt kann ich es durchaus nachvollziehen, mal davon abgesehen, dass die Idee ursprünglich gar nicht so sehr für Datentypen als für andere weitergehende Klarstellungen gedacht war. Ungefähr so, wie ich Datenbankfelder "received" oder "length" ablehne. "Received" kann von Boolean bis Datum alles sein, und zur "length" gehört eine Maßeinheit ODER ein zusätzliches Feld, dass die klärt. Besonders wenn man Amerikanische Kollegen hat.


    Aber davon ab finde ich Kritik wie "verwirrend" schlecht begründet. Man kann "ungarische Notation" durch "UPPER/ lower/ CamelCase/ Ersterbuchstabegroß" ersetzen, und die Begründung bleibt genauso gültig. Autotype ist schön, Umbenennen mit refactoring find ich aber noch viel schöner. DAS find ich mal echt geil, und das fehlt mir jetzt in VB6...

    "Für Primärschlüssel nimmt man heute GUIDs, auch wegen Replikation und so". Und dann haut EF da nen clustered Index drauf.

    Da solltest du mal erklären, was daran als default schlecht sein soll. Aber abgesehen davon: EF halte ich auch nicht für der Weisheit letzter Schluss. Wir halten davon bewusst Abstand.

    "Clustered" heisst zumindest beim SQLServer, dass die Datensätze physisch nach diesem Schlüssel sortiert abgelegt werden. GUID ist aber zumindest in der C#-Implementierung eine sehr zufällige Zahl, und Neuanlage von Datensätzen ist "drastisch" langsamer, und einen Mehrwert durch den Clustered hat man nicht mehr. Und die Sache mit der Replikation ist schön, aber solange 1 SQLServer für die Arbeit ausreicht würde ich Long bevorzugen. Joins über GUIDs sind nämlich auch nicht gerade schnell.

  • "Clustered" heisst zumindest beim SQLServer, dass die Datensätze physisch nach diesem Schlüssel sortiert abgelegt werden.

    Richtig, mit Hilfe eines B*-Tree

    GUID ist aber zumindest in der C#-Implementierung eine sehr zufällige Zahl, und Neuanlage von Datensätzen ist "drastisch" langsamer, und einen Mehrwert durch den Clustered hat man nicht mehr.

    Letzteres halte ich für ein Gerücht. GUID *soll* "sehr zufällig" sein, und das kommt einer Organisation im B*-Tree doch eher entgegen, weil es seltener die Notwenigkeit gibt, den ganzen Baum neu zu balancieren.

  • "Clustered" heisst zumindest beim SQLServer, dass die Datensätze physisch nach diesem Schlüssel sortiert abgelegt werden.

    Richtig, mit Hilfe eines B*-Tree

    GUID ist aber zumindest in der C#-Implementierung eine sehr zufällige Zahl, und Neuanlage von Datensätzen ist "drastisch" langsamer, und einen Mehrwert durch den Clustered hat man nicht mehr.

    Letzteres halte ich für ein Gerücht. GUID *soll* "sehr zufällig" sein, und das kommt einer Organisation im B*-Tree doch eher entgegen, weil es seltener die Notwenigkeit gibt, den ganzen Baum neu zu balancieren.

    Meines Wissens nach stecken normale Indexe in einem B+(?)-Tree, aber das sagt ja nichts darüber aus, wie die Records an sich gespeichert sind.

    Geschwindigkeit eines Testprogramms soll jedenfalls gegen einen Tree sprechen (wobei ich das nicht selber gemessen habe, sondern Kollegen).