Fragen zu einem C-Code

  • Hallo Leute!

    Auch wenn es das R-Basic-Forum ist, wollte ich mal einige Fragen zu einem C-Code stellen, den ich noch nicht ganz verstehe, aber im Idealfalle in R-Basic-Code wandeln möchte.
    Also es geht um diese schöne Funktion:

    Das wären meine Fragen dazu:

    • Frage 1: Das ist wohl die kleinste Frage, aber interessiert mich der Vollständigkeit halber doch. Welcher Grund ist vorstellbar, daß die Variable nrn als uint angelegt wird und i und dp als int? Auch i und dp starten ja bei null und werden im Code nur erhöht (können also nicht negativ werden). Einfach nur Zufall oder ist int schneller oder ...?
    • Frage 2: Werden die drei Variablen base, count und rd bei jedem Schleifendurchlauf neu angelegt (und mit null initialisiert)?
    • Frage 3: Hier stehen in einer if-Abfrage Zuweisung und Vergleich. Das hatte ich noch nicht. Bedeutet die linke Seite, daß erst rd berechnet und dann rd auf null verglichen wird? Könnte man das dann quasi auch so schreiben?

      Code
      if((rd = src[dp] & 0x0F) == 0 || nrn > 0){
      //evtl. äquivalent zu:
      rd = src[dp] & 0x0F
      if(rd == 0 || nrn > 0){
    • Frage 4: Diese Zeile verstehe ich so, daß ein weiteres Byte eingelesen und um vier Bit nach rechts verschoben wird, es wird also nur die obere Hälfte des Bytes verwendet. Aber welches Byte wird eingelesen?

      • Das gerade aktuelle Byte, von dem oben in der if-Schleife die untere Hälfte ausgewertet wurde, wird verwendet. Danach wird der Zähler dp erhöht.
      • Zuerst wird der Zähler dp erhöht und dann wird das Folge-Byte eingelesen und von dem linke Hälfte verwendet. Oder müßte dafür ++dp im Code stehen?
    • Frage 5: Bei der for-Schleife war ich kurz verwirrt, weil vor dem ersten Semikolon etwas fehlt. Aber da wurde wohl nur die Variablendeklaration weggelassen, weil ja count schon definiert ist?
      Hat es hier eine Bedeutung, ob da ++i oder i++ steht? Die Variable i startet ja mit null und wird nur hier in der for-Schleife erhöht. Man könnte ja denken, daß wegen ++i die Variable i erst erhöht und dann in der for-Schleife verwendet wird. Aber dann würde ja nie etwas bei i=0 geschrieben werden.

    Vielen Dank für alle Antworten :) !

    • Frage 1: der Grund ist in Zeile 14 zu finden - dort wird nrn aus der Variable src (also den Binärdaten, die dekodiert werden) geladen - und die ist uint8_t, weil die Daten byteweise interpretiert werden. Damit diese Zuweisung problemlos funktioniert, ist auch nrn als 8-bit-Wert deklariert.
    • Frage 2: zumindest wird bei diesem Geltungsbereich angenommen, dass die Werte nur innerhalb eines Schleifendurchlaufs verwendet werden. Über die Initialisierung wird nichts gesagt: es wird also nicht auf 0 initialisiert, wenn das nicht ausdrücklich dabei steht. Die Variablen haben also am Anfang der Schleife einen undefinierten Wert, der nicht garantiert ist und vom Compiler abhängt.
    • Frage 3: Ja, genau so ist es gemeint. Viele C-Programmierer mögen diesen Stil mit Zuweisungen in der Mitte von Ausdrücken auch nicht sehr, weil er leicht unübersichtlich wird und ein guter Compiler in beiden Fällen den gleichen Code erzeugen sollte.
    • Frage 4: Diese Darstellung liest erst das Byte an der Position dp ein und holt sich nur die oberen 4-bit davon. Anschließend wird dp um 1 erhöht. Wie du vermutestet, würde ++dp stattdessen das nächste Byte einlesen. Auch wieder so eine Optimierung mit "Seiteneffekten" (es wird nicht nur eine Variable geändert, sondern zwei), die aus Gründen der Lesbarkeit nicht unumstritten ist, aber für einfache, häufig vorkommende Aktionen wie "Byte holen und einen Schritt weitergehen" häufig verwendet wird, weil es eben schön kompakt ausdrückt, was man machen will.
    • Frage 5: in dieser speziellen Situation sind "++i" und "i++" gleichwertig, weil der Wert von i an dieser Stelle nicht verwendet wird. Das ist tatsächlich nur ein Befehl, der implizit als letzte Zeile der Schleife ausgeführt wird, und das Ergebnis der Rechnung ist egal. Der fehlende erste Teil bedeutet in der Tat, dass der aktuelle Wert von count einfach weiter gezählt wird.


    ciao marcus

  • Eine Frage hätte ich noch: Wie versteht ihr die Zeile 16? Dazu gibt’s im Quellcode noch eine Definition:

    Code
    #define get16(a) le16toh(*(uint16_t*)(a))
    
    
    base = get16(src + dp);        //Zeile 16 vom obigen Beitrag

    Mir scheint es ja, als ob ein 16-Bit-Wert eingelesen (im Little-Endian-Format) wird.
    Aber sonst steht immer src[x], was für mich das Byte an Position x bedeutet. Aber hier steht nur src! Was wird da genommen?

  • Der Ausdruck "src+dp" liefert dir einen Zeiger auf src[dp]. Zusammen mit dem ersten "*" im Makro hat das die gleiche Wirkung wie src[dp], aber hier eben erst, nachdem der Zeiger in einen Zeiger auf 16-bit Werte umgewandelt wurde.

    Diese etwas komplizierte Folge ist nötig, um zunächst die Zählung von dp in Bytes beizubehalten, dann aber von der Adresse am Ende zwei Bytes gleichzeitig zu holen.

    Und dann kommt noch le16toh() dazu, um ggf. die Reihenfolge von LE zu korrigieren.

    Ich würde persönlich eine etwas andere Form bevorzugen:

    Code
    base = src[dp] + (((uint16_t)src[dp+1])<<8);


    weil das ohne die LE-Funktion auskommt und das Umwandeln von 8-bit-Zeigern in 16-bit vermeidet, da manche Prozessoren Probleme haben, wenn man 16-bit-Werte von "ungeraden" Adressen lesen will. Aber das ist auch eine Stilfrage...