Warum sowas: (1u << 16) - 1

  • Dann ist aber auch der Begriff portabel unsinnig wenn Code nur auf einer bestimmten Platform laeuft und ein bestimmtes SDK genutzt wird. Ich dachte da etwas globaler

    Global denken ist gut und portabel ist nicht unsinnig. Wenn portabler Code nicht hinderlich ist, wird ein Programmierer das so machen (schon routinemäßig), auch dort wo es nicht sein müsste.

    The most popular websites without IPv6 in Germany.  IPv6-Ausreden

    Meine PIs

    PI4B/8GB (border device) OpenBSD 7.4 (64bit): SSH-Server, WireGuard-Server, ircd-hybrid-Server, stunnel-Proxy, Mumble-Server

    PI3B+ FreeBSD 14.0-R-p3 (arm64): SSH-Serv., WireGuard-Serv., ircd-hybrid-Serv., stunnel-Proxy, Mumble-Serv., ddclient

    PI4B/4GB Bullseye-lite (64bit; modifiziert): SSH-Server, WireGuard-Server, ircd-hybrid-Server, stunnel-Proxy, Mumble-Server, botamusique, ample

  • Ich weiss jetzt nicht ob ein Compiler bei einer 8 Bit CPU bei 0xffff meckern wuerde. Erwarten wuerde ich es jedenfalls.

    Arduino Uno, Nano oder Pro-Mini haben eine 8-bit CPU, und der C++ Compiler avr-g++ erlaubt int (16 bit) und long (32 bit) und float (32 bit) Operationen ohne zu meckern. 0xFFFF wird klaglos abgearbeitet, wenn man eine Konstante als long (32 bit) Wert bestimmen will, setzt man ein 'L' dahinter, also z.B. 0xFFFFL, Der Kompiler würde 0xFFFF als int erkennen, aber mit dem L dahinter wird es ein long. Manchmal kann das sinnvoll sein.

    Ich arbeite ausschliesslich mit C++ Compilern, und in C gibt es die minimale Konvention char = 8bit, short=16 bit, long=32 bit, float = 32 bit. Insofern ist eine Konstante 0xFFFF 100% portabel. Das war schon beim Intel 8051 so.

    Die Datentypen int , bool und double sind prozessorabhängig. Beim Arduino Uno z.B. ist int das selbe wie short und double  ist das selbe wie float.

    Assembler auf einer 8-bit Architektur ist eine komplett andere Baustelle, da muss sich der Programmierer selbst um die Datentypen kümmern. Da wird eine Fliesskomma Operation zur echten Herausforderung. Aber zum Glück gibts ja Compiler!

  • Da müsste man dann aber wohl ``(1L << 16) - 1`` schreiben, denn ein ``1u << 16`` ist entweder selbst schon undefiniert oder das abziehen von 1 von der resultierenden nicht vorzeichenbehafteten 0 ist es.

    stimmt. Da es aber funktioniert gehe ich davon aus dass der Compiler merkt dass der Ausdruck (1<<16) ein long ist. Das 'u' hinter der 1 verstehe ich sowieso nicht, das besagt dass die 1 ein unsigned int ist. Aber der Wert 1 kann ja nicht negativ sein, weil eine Konstante im Source Code immer erst mal als int interpretiert wird.

  • nurazur Das etwas ”funktioniert” heisst bei C erst einmal gar nichts wenn der Standard zu etwas sagt, dass es undefiniert ist. Das ist ja gerade das perfide daran, dass man Code schreiben kann der ”funktioniert”, weil der Compiler etwas macht was man erwartet, an einer Stelle wo er im Grunde machen kann was er will.

    Das `u` ist nötig weil ein Überlauf bei ``<<`` bei `int` undefiniertes Verhalten ist, während bei `unsignet int` die Bits einfach rausgeschoben werden/verloren gehen. Und ähnliches gilt dann auch für das abziehen von 1 falls beim ``<<`` eine 0 heraus kommt, was wie gesagt nicht garantiert ist.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • du hast einen Punkt. nach 40 Jahren Praxis in C Programmierung hab ich wieder mal was gelernt :).


    weil ein Überlauf bei ``<<`` bei `int` undefiniertes Verhalten ist, während bei `unsignet int` die Bits einfach rausgeschoben werden/verloren gehen.

    Das steht so nicht im Standard, jedenfalls nicht in meinem (damals ANSI C, also K&R, heute als C89 bzw C90 Standard bezeichnet).


    Im C Standard steht:

    Zitat

    "Die shift-Operatoren << und >> werden von links nach rechts zusammengefasst. Bei beiden Operatoren muss jeder Operand ein Integer-Wert sein und Integer-Erweiterung findet statt. Der Resultattyp ist der Typ des erweiterten linken Operanden."

    Jetzt kommts:

    Zitat

    Das Resultat ist undefiniert, wenn der rechte Operand negativ ist oder wenn der Wert des rechten Operanden nicht kleiner ist als die Länge des linken Operanden in Bits.

    Demnach müsste es korrekt (1L<<16)-1 heissen, das u verstehe ich zwar jetzt, ergibt aber keinen Sinn. Zur Sicherheit koennte man ja (1UL<<16)-1 schreiben.

    Da aber die Typ-Erweiterung im Kompiler automatisch abläuft, ist der Zusatz nicht notwendig. Eine Schiebeoperation um 16 bits sagt dem Kompiler dass der linke Operand mindestens 17 bits haben muss (laut ANSI C Standard), also erweitert er den Typen auf long. Ob das jetzt signed oder unsigned ist ist egal.

  • ..., das u verstehe ich zwar jetzt, ergibt aber keinen Sinn.

    Evtl. wollte der Programmierer, bei manchen Compilern, mit dem u, nur Warnmeldungen vermeiden. Lt. Beitrag #14 ist in der Definition der Funktion, "void pio_pwm_set_period(PIO pio, uint sm, uint32_t period)".

    The most popular websites without IPv6 in Germany.  IPv6-Ausreden

    Meine PIs

    PI4B/8GB (border device) OpenBSD 7.4 (64bit): SSH-Server, WireGuard-Server, ircd-hybrid-Server, stunnel-Proxy, Mumble-Server

    PI3B+ FreeBSD 14.0-R-p3 (arm64): SSH-Serv., WireGuard-Serv., ircd-hybrid-Serv., stunnel-Proxy, Mumble-Serv., ddclient

    PI4B/4GB Bullseye-lite (64bit; modifiziert): SSH-Server, WireGuard-Server, ircd-hybrid-Server, stunnel-Proxy, Mumble-Server, botamusique, ample

    2 Mal editiert, zuletzt von rpi444 (4. September 2021 um 12:15)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!