Hallo,
und zwar stehe ich vor einem Problem in der Programmiersprache C, bis
jetzt habe ich es noch nicht geschaft das Problem zu lösen, vieleicht
schaft es ja ein C-Spezialist unter euch....
Folgendes Problem:
Es soll ein unsigned character und ein signed character addiert werden,
dabei sollen wie die Namen schon sagen, dem unsigned der volle
Wertebereich zur Verfügung stehen und dem unsigned von -127 bis 128.
Jedoch sollen die Überläufe abgefangen werden d.h es darf nie kleiner 0
und nie größer 255 werden.
Ich habe schon begonnen das Problem zu lösen und schaffe es auch das der
Unterlauf abgefangen wird also die Variable wird nie kleiner 0, aber der
Überlauf über 255 klappt nicht....vieleicht hat einer von euch eine
bessere Idee.
hier mal Stück C-Code:
Berechne das Ergebnis doch zunächst mal als int (z.B. mittels temporärer
Hilfsvariable). Dann prüfst Du auf den geforderten Wertebereich und
machst anschließend die entsprechende Zuweisung für motor1.
Sehe grad das Problem nicht. Gerechnet wird
unsigned_char + signed_char
formal sowieso in int, also mit grössere Breite. Das ausnutzen und
anschliessend auf 0..255 clippen ist nicht weiter schwierig.
> Jedoch sollen die Überläufe abgefangen werden d.h es darf nie> kleiner 0 und nie größer 255 werden.
Das geht nicht.
C ist explizit so definiert, daß das Ergebnis in deinem Fall überrollt.
Wenn du in deiner Berechnung Überläufe abfangen willst, mußt du als
temporären Zwischenwert einen entsprechend größeren Datentyp benutzen.
Überhaupt verstehe ich den Hintergrund nicht ganz.
'signed' und 'unsigned' sind quasi zwei verschiedene Interpretationen
ein und derselben Speicherzelle. Das ist das gleiche wie Äpfel und
Birnen addieren...
frame schrieb:> C ist explizit so definiert, daß das Ergebnis in deinem Fall überrollt.
Nein. Zumindest nicht solange sizeof(char) < sizeof(int), da das
Zwischenergebnis vom Typ int ist. Erst durch eine anschliessende
Truncation zu unsigned char geschieht dies.
wieso sollten das Unterschiede sein? nur die Interpretation des
Zahlenkreis ist anders z.b 27 in unsigned ist das gleich in signed aus
Bitebene. Nur negative Zahlen sind etwas anders. Ich mache mal ein
kleines Bsp dazu vieleicht wird es dann klarer wo es hin soll...
Mit positven Zahlen:
200 + 40 = 40
200 + 60 = 255
Mit negativen Zahlen:
100 + (-60) = 40
100 + (-120) = 0
Hintergrund ist: ein Motor soll ein Stellsignal in einem postiven
Bereich von 0-255 von einer Fernsteuerung bekommen, das Signal wird aus
2 Hebeln der Steurung gemischt eben aus Pitch und aus Nick das auch
negativ werden kann.....
Danke den Tipp mit dem größen Zahlenbereich werde ich mal testen...
Simo schrieb:> Ich mache mal ein> kleines Bsp dazu vieleicht wird es dann klarer wo es hin soll...>> Mit positven Zahlen:> 200 + 40 = 40>> 200 + 60 = 255>> Mit negativen Zahlen:> 100 + (-60) = 40>> 100 + (-120) = 0
Bist Du sicher das dies auf allen Hardwareplatformen der Fall ist (zB
auf Mainframes* (ja, dafür gibt's auch C compiler))?
* IBM, UNISYS, SPERRY UNIVAC
Norbert schrieb:> Bist Du sicher das dies auf allen Hardwareplatformen der Fall ist
Hardwareseitige Saturierung ist eher für DSPs und MMX/SSE/...
Befehlssätze typisch - ein Bereich, in dem sich Mainframes eher selten
bewegen.
Wenn er das softwareseitig abfängt: Wo sollten Probleme auftauchen? Ok,
signed char definiert nur -127..+127, aber das ist die einzige
Einschränkung.
Ja klar, na gut teilweise. Check mal bei der Lusthansa ein
(Ticket-Gateways Unisys)
Dabei hab ich mich noch nicht einmal getraut meinen guten alten
Perkin-Elmer zu nennen (erste 'C' Gehversuche)
J.-u. G. schrieb:> frame schrieb:>> Das ist das gleiche wie Äpfel und>> Birnen addieren...>> Du meinst, bei der Rechnung x = 100 + (-50) werden Apfel und Birne> adddiert?
Nein. Die Werte sind beide vorzeichenbehaftet. Nur weil ein Wert positiv
ist, macht ihn das ja nicht automatisch vorzeichenlos.
Nochmal:
In C gibt es eine Regel. Die besagt, dass Berechnungen grundsätzlich
mindestens im kleinsten Datentyp 'int' ausgeführt werden. Es spielt
schlicht und ergreifend keine Rolle ob du einen unsigned char mit einem
signed char addierst. Denn als erstes werden beide Additionspartner
sowieso zu einem int 'befördert', ehe dann die Addition ausgeführt wird.
Genau darum funktioniert deine Version. Denn das Ergebnis von
stick_pitch + stick_nick
ist bereits ein int. Auch ohne Cast.
PS: Wenn du mit dem Cast sicherstellen wolltest, dass auch ein schräg
konfigurierter µC-Compiler das in 16 Bits rechnet - manche sind so
einstellbar, dass standardwidrig aber effizienter keine Erweiterung
auf int stattfindet - dann funktioniert das so nicht. Dann würde der es
in 8 Bit Rechnung addieren und erst das falsche Ergebnis zu 16 Bits
machen.
Dann geht das so:
temp_vari = (int16_t)stick_pitch + (int16_t)stick_nick;
danke, das wusste ich garnicht, dass ehh alles in integer gerechnet
wird. Ist das nicht Ressourcenverschwendung?
Habe bis jetzt immer in Assembler gerechnet da war immer("meistens" :-)
) klar was an welcher Stelle passiert....
Simo schrieb:> danke, das wusste ich garnicht, dass ehh alles in integer gerechnet> wird. Ist das nicht Ressourcenverschwendung?
Das ist nun einmal so definiert - und anfangs war es auch keine
Resourcenverschwendung, weils die damals in C massgebliche PDP-11 intern
sowieso in genau dieser Weise gerechnet hat.
Simo schrieb:> danke, das wusste ich garnicht, dass ehh alles in integer gerechnet> wird. Ist das nicht Ressourcenverschwendung?
Jain.
Es steht ja dem Optimizer frei, das Ganze wieder umzustossen, wenn er
nachweisen kann, dass das Ergebnis dasselbe ist, wenn er anstelle einer
16-Bit Berechnung auf 8 Bit runterkürzt.
>> Habe bis jetzt immer in Assembler gerechnet da war immer("meistens" :-)> ) klar was an welcher Stelle passiert....
AUch hier ist es klar, wenn man sein C gelernt hat.
Und genau aus dem Grund schreib ich mitlerweile unter jeden 3.ten Thread
drunter: Kauf dir ein C-Buch! Da stehen solche Sachen (und noch 100-erte
andere) nämlich drinnen.
also ich habe ein C-Buch, dass ist vieleicht nicht das Dickste und
Beste, aber die Grundlagen stehen drin, allerdings besonders auf
Berechnungen solcher Art werden nicht eingegangen!!! Welcher Buch kannst
du denn empfehlen, in dem auch solch Dinge stehen @ Karl Heinz
Buchegger?
Simo schrieb:> also ich habe ein C-Buch, dass ist vieleicht nicht das Dickste und> Beste, aber die Grundlagen stehen drin, allerdings besonders auf> Berechnungen solcher Art werden nicht eingegangen!!! Welcher Buch kannst> du denn empfehlen, in dem auch solch Dinge stehen @ Karl Heinz> Buchegger?
Wie immer den Klassiker
Kernighan & Ritchie
Programmieren in C
Wenn geht, die englische Original-Version. (keine Angst. das ist eine
technische Doku und kein literarisches Meisterwerk. Mit Schulenglisch
kommt man gut zurecht)
A. K. schrieb:> Wenn er das softwareseitig abfängt: Wo sollten Probleme auftauchen? Ok,> signed char definiert nur -127..+127, aber das ist die einzige> Einschränkung.
Wenn es C ist stlopert man gerne darüber daß signed-Overflow undefined
ist:
Einfach mal mit einem nicht allzu alten GCC compilieren.
Neben diesem händischen Saturieren gibt es auch die Embedded-C
Erweiterung ISO/IEC TR 18037, die saturierte Arithnmetik implementiert.
Einige Compiler wie avr-gcc unterstützen diese C-Erweiterung.
Hallo,
ich dachte immer, Berechnungen werden im größeren der beiden Datentypen
durchgeführt, die an der Rechnung beteiligt sind?
Vor einiger Zeit hab ich mal einen uint16 mit einem Konstanten Wert von
3000 multipliziert. Erst nachdem ich hier im Forum nachgefragt und einen
Faktor nach uint32 gecastet habe hats geklappt. Auf einem AVR entspricht
INT aber einem 32Bit Datentyp, also hätte doch der Cast nicht notwendig
sein dürfen?
Kann mal schaun ob ich den Thread noch finde...
Karlo schrieb:> ich dachte immer, Berechnungen werden im größeren der beiden Datentypen> durchgeführt, die an der Rechnung beteiligt sind?
Auch. Aber mindestens in "int". Steht in jedem C Handbuch.
> Auf einem AVR entspricht INT aber einem 32Bit Datentyp
Was immer ein INT ist - ein int hat bei AVRs 16 Bits.