Hallo Leute, Ist das Rechtsschieben von signed eigentlich im Standard definiert? Kann ich davon aus gehen, dass folgendes definiert ist: ??? Uint16 foo = 0x8000; Foo>>=2; // 0x2000 Int16 foo = 0x8000; Foo >>= 2; // 0xe000 Fur welche Operanden ist eigetlich der Shiftoperator definiert? Ich möchte einen linksbündigen 14bit A/D Wert normieren. Danke, Adib. --
Adib schrieb: > Hallo Leute, > > Ist das Rechtsschieben von signed eigentlich im Standard definiert? In welchem? > Kann ich davon aus gehen, dass folgendes definiert ist: > ??? > Uint16 foo = 0x8000; > Foo>>=2; // 0x2000 > > Int16 foo = 0x8000; > Foo >>= 2; // 0xe000 Falls es um C gehen sollte, nein. > Fur welche Operanden ist eigetlich der Shiftoperator definiert? Beide Operanden dürfen nicht negativ sein, und bei einem vorzeichenbehafteten Typ muss das Ergebnis (linker Wert mal zwei hoch rechter Wert) darstellbar sein. > Ich möchte einen linksbündigen 14bit A/D Wert normieren. Und der ist vorzeichenbehaftet?
Ok, hier muss ich nochmal korrigieren. War irgendwie vom Linksschieben ausgegangen. Beim Rechtsschieben von negativen Werten ist das Ergebnis implementationsabhängig.
Rolf Magnus schrieb: > Beim Rechtsschieben von negativen Werten ist das Ergebnis > implementationsabhängig. Und: Wenn beim Linksschieben einer vorzeichenbehafteten Ganzzahl das Vorzeichen betroffen ist, dann ist das Ergebnis undefiniert. https://msdn.microsoft.com/de-de/library/336xbhcz.aspx Aber wo ist nun die Standart-Definition zu lesen, ohne sich die Bücher kaufen zu müssen?
C11: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf C99: http://web.cse.ohio-state.edu/~rountev/3341/pdf/C.pdf
Also laut pdf C99: 6.5 Expressions, Absatz 4 Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) are required to have operands that have integer type. These operators yield values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types. undefined behavour :-( ok. Danke das wars, was ich wissen wollte. In meinem Code schiebe ich jetzt nicht mehr die Daten nach rechts um 2, sondern dividiere durch 4. Der Compiler macht dann ein "Arithmetic right shift". Grüße, Adib. --
Da gibt's noch eine etwas konkretere Passage in 6.5.7: The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
Shift ist ein Bitoperator. Dabei spielt die Interpretation keine Rolle. Egal ob int float char oder sonst was. Du möchtest aber dividieren. Also schreib das einfach hin und lass den Compiler das für dein Target optimal umsetzen.
compiler schrieb: > Shift ist ein Bitoperator. Dabei spielt die Interpretation keine Rolle. > Egal ob int float char oder sonst was. In Assembler vielleicht, aber nicht in C. Für float ist eine Schiebeoperation nicht mal definiert. > Du möchtest aber dividieren. Eigentlich nicht. Das ADC-Ergebnis ist links ausgerichtet, und Adib möchte es so verschieben, dass es rechts ausgerichtet ist. Das Problem besteht darin, dass der ADC-Wert vorzeichenlos ist, aber offenbar fälschlicherweise in einer vorzeichenbehafteten Variable gespeichert ist.
Rainer V. schrieb: > Aber wo ist nun die Standart-Definition zu lesen Hier: http://www.k-faktor.com/standart/
Im übrigen kann ich mir auch nicht vorstellen, dass eine Division durch 4 hier korrekt ist. Im obigen Beispiel Adib schrieb: > Int16 foo = 0x8000; hat foo hier den Wert -32768. Nach der Division ist er -8192, was dann 0xE000 entspricht. Eigentlich sollte aber 0x2000 rauskommen.
Es gibt AD-Wandler, die ihre Ergebnisse im Zweierkomplement ausgeben. Wenn man nicht sicher ist, ob der Compiler vorzeichenrichtig rechts schieben kann bzw. aus einer /4 Division ein schnelles Shift macht, dann halt so.
1 | int x = ADC_Wert; |
2 | |
3 | x >>= 2; |
4 | if (x & 0x2000) x |= 0xC000; |
Hallo Falk, & andere der Sensor liefert einen 14bit vorzeichenbehafteten Wert. BMA280 Bosch Bechleunigungssensor. Der ist linksbündig. Die 2 bit LSB sind einfach Flags, die man irgnorieren kann. bei einem Sensorresultat von 0x8000 lautet das normalisierte Ergebnis 0xe000 Ich hätte das Vorzeichen testen müssen und entsprechend 0xc000 bitwise or machen müssen. C hat leider kein Arithmetic shift oder irgendsoeinanders shift vom Prozessor. oben steht bei signed typ und negativen Wert ist das Verhalten implementation specific. Ich hatte schon mal beobachtet, das das mit dem Schieben sogar vorzeichenkorrekt funktioniert. Wusste aber nicht, ob ich mich darauf verlassen kann, oder ob bei der nächsten Compilerversion oder bei einem anderen Compiler das genau anders ist. Bei / 4 ist die Sache eigentlich klar. Wenn ich den Code auf den AVR übertrage muss ich dann halt schauen, ob er auch shiftet oder eine div Subroutine aufruft. GRüße, Adib. --
Adib schrieb: > der Sensor liefert einen 14bit vorzeichenbehafteten Wert. BMA280 Bosch > Bechleunigungssensor. Ah, ok. Dann ist das natürlich was anderes. > C hat leider kein Arithmetic shift oder irgendsoeinanders shift vom > Prozessor. Kann sein, dass der Compiler den nutzt. Es ist ja immerhin implementation-defined, muss also vom Compiler festgelegt und in dessen Handbuch dokumentiert sein, wie er es macht. Wenn's unabhängig vom Prozessor und Compiler sein soll, kannst du dich natürlich nicht drauf verlassen. > Ich hatte schon mal beobachtet, das das mit dem Schieben sogar > vorzeichenkorrekt funktioniert. Ich würde vermuten, dass das sogar eher die Regel als die Ausnahme ist. > Bei / 4 ist die Sache eigentlich klar. Ja. Das muss der Compiler vorzeichenrichtig machen. > Wenn ich den Code auf den AVR übertrage muss ich dann halt schauen, ob er > auch shiftet oder eine div Subroutine aufruft. Ein halbwegs optimierender Compiler sollte das hinbekommen.
Adib schrieb: > sondern dividiere durch 4. > Der Compiler macht dann ein "Arithmetic right shift". Dann macht der Compiler es falsch. -1 / 2 = 0 -1 >> 1 = -1
Warnt GCC beim Versuch, eine signed bzw. float Variable zu shiften? Wenn nein, wie lässt sich diese Warnung einschalten?
Julius Z. schrieb: > Warnt GCC beim Versuch, eine signed bzw. float Variable zu shiften? Wenn > nein, wie lässt sich diese Warnung einschalten? Beim Versuch, eine float-Variable zu shiften, gibt es einen Fehler. Bei vorzeichenbehafteten Integern wüßte ich nicht, dass man eine Warnung einstellen könnte. Wäre vermutlich auch recht sinnlos, da vor jeder Operation alle Operanden, die kleiner als int sind, erstmal auf int erweitert werden und damit ein Vorzeichen bekommen.
Adib schrieb: > Some operators (the unary operator ~, and the binary operators <<, >>, > &, ^, and |, > collectively described as bitwise operators) are required to have > operands that have > integer type. These operators yield values that depend on the internal > representations of > integers, and have implementation-defined and undefined aspects for > signed types. Wenn GCC z.B. ein uint8_t, das man shiften möchte, zu int promoted, wird dann damit nicht undefiniertes Verhalten absichtlich provoziert? Klar, wenn vorher kein Vorzeichen drin war und die Bitbreite anschließend höher ist, kann theoretisch nichts passieren... aber laut Dokumentation ist es undefined...
Für positive Werte ist es klar definiert. Beitrag "Re: Signed korrektes Rechtsschieben"
:
Bearbeitet durch User
Julius Z. schrieb: > aber laut > Dokumentation ist es undefined... Nein, es ist implementation defined. Das ist ein Unterschied. Und das auch nur für negative Zahlen. Wenn ein uint8_t oder uint16_t auf int promoted wird, ist es immer ein positives int. Also völlig ok.
Habe es für den avr-gcc mal getestet: Dort funktioniert es so, wie man es sich mathematisch korrekt vorstellt. Schiebt man z.B. -1 nach links, ergibt das -2. Schiebt man -2 nach rechts, ergibt das -1. Das Vorzeichen-Bit wird also nicht unkontrollierbar in den Zahlenwert hineingemurkst, sondern behandelt. Das gilt, wie gesagt, für den avr-gcc. Woanders sieht es sicher anders aus.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.