Forum: Mikrocontroller und Digitale Elektronik Frage zu type cast in C


von Daniel S. (supernova01)


Lesenswert?

Hallo,

kleine Frage, ich habe folgendes:

int8_t diff=-102;

uint8_t out=0;

nun steht ja in diff die Bitfolge 0x9A, also b10011010.

Ich möchte nun aber die 102 als positive Ganzzahl (0x66-b01100110) in 
out stehen haben.

geht das so?

out=(uint8_t)diff;

oder so:

out=(diff-1)^0xFF;

Habe gerade einen Knoten im Hirn.

Danke
DS

von Adam P. (adamap)


Lesenswert?

Das wäre am einfachsten, oder suchst du eine Lösung mit Bit-Operation 
ohne "Hilfsfunktionen"?
1
out = abs(diff);

edit:
so gehts auch:
1
out = (diff * -1);

oder:
1
out = (diff ^ 0xFF) + 1;

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Dennis S. schrieb:
> nun steht ja in diff die Bitfolge 0x9A, also b10011010.

Nein, dieses ist  Implementation Defined, somit nicht als gesichert 
anzunehmen

von Peter D. (peda)


Lesenswert?


von MaWin (Gast)


Lesenswert?

out = (uint8_t)-diff;

von P. S. (namnyef)


Lesenswert?

Selbst abs() kann zu undefiniertem Verhalten führen, weil der Betrag der 
kleinsten negativen Zahl in Zweierkomplementdarstellung größer ist als 
die größte positive Zahl. Die Verwendung dieser Funktion ist aber der 
naheliegendste erste Ansatz bevor man Murks auf Bit-Ebene fabriziert.

Ob das undefinierte Verhalten von abs() relevant ist, muss je nach 
Anwendung beurteilt werden.

von Adam P. (adamap)


Lesenswert?

P. S. schrieb:
> Selbst abs() kann zu undefiniertem Verhalten führen

Also laut GNU C ist abs() so implementiert:
1
/* Return the absolute value of I.  */
2
int
3
abs (int i)
4
{
5
  return i < 0 ? -i : i;
6
}

P. S. schrieb:
> weil der Betrag der kleinsten negativen Zahl in Zweierkomplementdarstellung > 
größer ist als die größte positive Zahl.

Das würde stimmen, wenn du es wieder einem int8_t zuweisen möchtest,
aber nicht wenn du als Ziel uint8_t verwendest.
1
// Das ergibt wieder -128
2
int8_t i = -128;
3
4
i = abs(i);

Oder sehe ich da jetzt etwas falsch?

: Bearbeitet durch User
von Daniel S. (supernova01)


Lesenswert?

Adam P. schrieb:
> Oder sehe ich da jetzt etwas falsch?

Der Betrag von -128 ist 128.

Der Zahlenbereich eines int8_t geht von -128 bis 127.

Ich denke das war gemeint. Also der Betrag von -128 passt nicht in eine 
int8_t.

P. S. schrieb:
> Ob das undefinierte Verhalten von abs() relevant ist, muss je nach
> Anwendung beurteilt werden.

Das wäre aber ja nur ein Problem wenn man den Rückgabewert wieder einem 
int8_t zuspielt. In meinem Fall geht er in einen uint8_t, der geht ja 
bis 255...

MaWin schrieb:
> out = (uint8_t)-diff;

tatsächlich so einfach. probiere ich aus, nachher.


EAF schrieb:
> Nein, dieses ist  Implementation Defined, somit nicht als gesichert
> anzunehmen

Was wäre denn "sicher", oder wasserdicht und üblich?

Danke bis hierher.

von Adam P. (adamap)


Lesenswert?

Dennis S. schrieb:
> Das wäre aber ja nur ein Problem wenn man den Rückgabewert wieder einem
> int8_t zuspielt.

So habe ich es ja geschrieben.

von Hannes (Gast)


Lesenswert?

Dennis S. schrieb:
> Habe gerade einen Knoten im Hirn.

Meine Tipp: Meide Type-Cast auf Teufel komm raus!

Notwendig erscheinende Casts sind fast immer ein Zeichen, dass mit den 
Datenstrukturen irgendwas faul ist.

Die Warnings oder Errors, die man mit wilden Casts meint unterdrücken zu 
müssen, schmeißt der Compiler aus einem ganz bestimmten Grund, 
namentlich weil er hier Probleme erkannt hat. Dies, wie Muttis lästige 
Händi-Anrufe einfach wegzudrücken ist sicher nicht der beste Weg -- 
sondern gleicht eher einer Vogelstrauß-Taktik.

just my 2 ct

von Oliver S. (oliverso)


Lesenswert?

Hannes schrieb:
> Meine Tipp: Meide Type-Cast auf Teufel komm raus!

Damit schliesst du für dich das Rechnen mit Datentypen, die kleiner als 
ein Int sind, faktisch aus.

Oliver

von Wf88 (wf88)


Lesenswert?

Wenn du einfach nur das Vorzeichen entfernen willst, dann musst du nur 
das höchstwertige Bit löschen.
1
int8_t byte = 0xFF;
2
int16_t word = 0xFFFF;
3
uint16_t result;
4
5
result = (byte & ~0x80);
6
result = (word & ~0x8000);

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Wf88 schrieb:
> Wenn du einfach nur das Vorzeichen entfernen willst, dann musst du
> nur
> das höchstwertige Bit löschen.

Das stimmt zwar, ist aber nur sinnvoll, wenn der Zahlenwert keine Rolle 
spielt. Das ist eher selten…

Oliver

von Dirk B. (dirkb2)


Lesenswert?

Wf88 schrieb:
> Wenn du einfach nur das Vorzeichen entfernen willst, dann musst du nur
> das höchstwertige Bit löschen.
>
>
1
> int8_t byte = 0xFF;
2
> int16_t word = 0xFFFF;
3
> uint16_t result;
4
> 
5
> result = (byte & ~0x80);
6
> result = (word & ~0x8000);
7
>

Wegen Integer Promotion kommt beim byte nicht das raus, was du 
erwartest.

von MaWin (Gast)


Lesenswert?

Wf88 schrieb:
> Wenn du einfach nur das Vorzeichen entfernen willst, dann musst du nur
> das höchstwertige Bit löschen.

Im Zweierkomplement ist das leider völliger Unsinn.

von Hannes (Gast)


Lesenswert?

Oliver S. schrieb:
> Hannes schrieb:
>> Meine Tipp: Meide Type-Cast auf Teufel komm raus!
>
> Damit schliesst du für dich das Rechnen mit Datentypen, die kleiner als
> ein Int sind, faktisch aus.
>
> Oliver

Wär mir neu - aber vielleicht reden wir auch von ganz verschiedenen 
Dingen?

Jedenfalls hattest Du bei meinem AG deine liebe Not, beim 'code review' 
einen Cast durchgeboxt zu kriegen.

-H

von A. S. (Gast)


Lesenswert?

warum nicht straight:
1
if(diff >= 0) {out = diff;} else {out = -diff;}

Es ist müßig, irgendwelche halbgaren Tricks oder Standard-Funktionen zu 
vergewaltigen, um ein offensichtliches if zu sparen. Und Casts brauchts 
auch nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dennis S. schrieb:
> out=(uint8_t)diff;

Das ergibt übrigens 154 statt deiner gewünschten 102. Es wird nur das 
Bitmuster kopiert, ohne jede Rechnung.
1
out=(uint8_t)-diff;

würde gehen.

von Rolf M. (rmagnus)


Lesenswert?

Hannes schrieb:
> Dennis S. schrieb:
>> Habe gerade einen Knoten im Hirn.
>
> Meine Tipp: Meide Type-Cast auf Teufel komm raus!

Mein Tipp wäre eher: Lerne zu verstehen, wo und warum Casts nötig sind. 
Das hilft dabei, sie zu vermeiden, wo sie nicht nötig sind und korrekt 
anzuwenden, wo sie es sind.
Anders gesagt: Immer, wenn man einen Cast hinschreibt, sollte man genau 
sagen können, was er an der Stelle bewirkt und warum er dort 
unvermeidbar ist.

> Die Warnings oder Errors, die man mit wilden Casts meint unterdrücken zu
> müssen, schmeißt der Compiler aus einem ganz bestimmten Grund,
> namentlich weil er hier Probleme erkannt hat. Dies, wie Muttis lästige
> Händi-Anrufe einfach wegzudrücken ist sicher nicht der beste Weg --
> sondern gleicht eher einer Vogelstrauß-Taktik.

Das ist richtig. Der Grund für einen Cast darf niemals sein: "Um die 
Compiler-Warnung wegzubekommen".

Oliver S. schrieb:
> Hannes schrieb:
>> Meine Tipp: Meide Type-Cast auf Teufel komm raus!
>
> Damit schliesst du für dich das Rechnen mit Datentypen, die kleiner als
> ein Int sind, faktisch aus.

Warum?
1
#include <stdio.h>
2
#include <inttypes.h>
3
int main(void)
4
{
5
    uint8_t a = 23:
6
    uint8_t b = 45;
7
    uint8_t c = a + b;
8
    printf("%" PRIu8 "\n", c);
9
}
Ganz ohne Casts.

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.