mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Warum diese Subtraktion


Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

ich bin hier grade auf etwas gestoßen, dass mir komisch und überflüssig 
erscheint.

Es geht um folgenden Codeausschnitt:
short data[7];
char currentData;

if(i != 0 && i < 3)  
{
  if(currentData & 0x80)              // MSB des Zweierkomplements vorhanden ?
  {    
    data[i] = data[i] + (currentData - 256);  // Subtraktion von der Gesamtsumme
  }
  else
    data[i] = data[i] + currentData;      // Addition zur Gesamtsumme
}

Dieser Code ist aus einem Programm für einen PIC18F2520 und es wurde ein 
HITECH PICC18 Compiler benutzt.

Ich soll nun erstmal das Programm für neue Hardware mit einem AVR 
portieren.

currentDara ist ein char (nicht unsigned) und wird von einer 8 Bit 
Software SPI geselen, welche einen unsigned char zurück gibt.

Das Array data wird iteriert (i Laufindex). Ich hoffe ich nehme richtig 
an, dass ein short genau wie ein int 16 Bit beträgt.

In den Felder data[1] und data[2] wird eine Summe gebildet. Da 
currentData auch negativ sein kann (Zweierkomplement) wird hier per 
if-else geprüft ob es positiv oder negativ ist.

Im positiven Fall wird einfach addiert. Im negativen Fall wird erstmal 
der Wert 256 abgezogen und dann addiert.

Warum wird 256 abgezogen? Normal sollte eine Addition doch ausreichen 
und das if-else ist überflüssig.
Übersehe ich den Grund für diesen Umweg über das if-else und die 
Subtraktion oder ist dieses gebilde wirklich überflüssig und kann durch 
data[i] += currentData ersetzt werden?

Autor: Thomas K. (muetze1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Er prüft ob das MSB gesetzt ist, was eine negative Zahl anzeigt. Wenn 
diese erkannt wurde (Bit gesetzt), will er den Wert binär invertieren um 
dadurch die entsprechende Ziffer zu erhalten als Positivzahl. Dieses 
binäre invertieren erreicht er nun durch die Subtraktion (Alternative).

Autor: Matthias F. (flint)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vorzeichen erhalten wenn der 8 bit wert in einen 16 bit wert gewandelt 
wird? kommt mir aber hatschert vor.

lg
m

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
poste doch mal die ganze Routine.

Das ganze sieht sowiso recht komisch aus

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mir mal folgendes im Simulator angeguckt
  char foo = 0xFF;
  char bar = 100;
  PORTA = bar;
  bar += foo; //Ergebnis 99
  PORTB = bar;
  bar = bar + (foo - 256); //Ergebnix 98
  PORTC = bar;
Da sehe ich keinen unterschied, ob ich die negative Zahl einfach 
addiere, oder erst 256 abziehe.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
martin schrieb:
> Warum wird 256 abgezogen? Normal sollte eine Addition doch ausreichen
> und das if-else ist überflüssig.

Vermutlich wird damit ein Bug des Compilers korrigiert.

Du hast recht, bei einem funktionierenden Compiler ist dieser Code 
überflüssig, er macht automatisch die vorzeichenrichtige Erweiterung 
einer 8Bit-Zahl auf 16 Bit.


Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht ist auf diesem Compiler aber auch einfach nur ein char als 
Default ein unsigned char.

Wie ich immer sage:
  char  ausschliesslich für Texte reservieren

In allen anderen Fällen immer explizit sein. Entweder signed oder 
unsigned char benutzen.

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK was ich auch seltsam finde ist folgendes:
  unsigned char foobar = 0xFF;
  char foo = foobar;
  short bar = 100;
  PORTA = bar>>8;
  bar += foo;
  PORTB = bar>>8;
  bar = bar + (foo - 256);
  PORTC = bar>>8;
PORTA -> 0x00
PORTB -> 0x01
PORTC -> 0x01

Wo kommen die Einsen her?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Code funktioniert ohnehin nur, wenn "char" vorzeichenlos ist. Wer 
davon unabhängig sein will sollte ein &0xFF einbauen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
martin schrieb:

> Wo kommen die Einsen her?

100 + 255 = 356 = 0x16D
0x16D >> 8 = 1

356 + (255 - 256) = 355. Dito.

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich vermute mal char ist per default unsigned, und der Schreiber moechte 
den Wert als signed char zu data[i] dazuaddieren.

Das wird schief gehen, wenn dieser Code mal auf ein char trifft, das per 
default signed ist.

Richtig waere eine Deklaration von currentData als signed char, dann ist 
das eine einfache Addition.

Juergen

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Juergen schrieb:

> Richtig waere eine Deklaration von currentData als signed char, dann ist
> das eine einfache Addition.

Auch das setzt aber voraus, dass ein char aus 8 Bits besteht.

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wird hier einfach ein char als unsigned char interpretiert und 
daher die 0xFF als 255 und nicht als -1?

Wenn ich aber
  unsigned char foobar = 0xFF;
  char foo = foobar;
  short bar = 100;
  PORTA = bar&0xFF;
  bar += foo;
  PORTB = bar&0xFF;
  bar = bar + (foo - 256);
  PORTC = bar0xFF;
schreibe, dann passt es
PORTA -> 0x64
PORTB -> 0x63
PORTC -> 0x62

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meint ihr das sollte so funktionieren? (avr-gcc)
int16_t data[7];
int8_t currentData;

currentData = (int8_t)spi_read(); // spi_read gibt einen uint8_t zurück

if(i != 0 && i < 3)  
{
  data[i] += currentData;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
martin schrieb:
> Meint ihr das sollte so funktionieren? (avr-gcc)
>
> int16_t data[7];
> int8_t currentData;
> 
> currentData = (int8_t)spi_read(); // spi_read gibt einen uint8_t zurück
> 
> if(i != 0 && i < 3)
> {
>   data[i] += currentData;
> }
> 

Ich denke, dass genau das die ursprüngliche Absicht war.
(Kaum macht man es richtig, werden viele seltsam kryptischen Codestellen 
oftmals ganz einfach :-)

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, dann werde ich das so benutzen und mich weiter durch einen 
Haufen, nicht gut wartbaren, Code kämpfen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.