Warum diese Subtraktion

Gast #1343545
Lesenswert?

Moin,

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

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

4
if(i != 0 && i < 3)  
5
{
6
  if(currentData & 0x80)              // MSB des Zweierkomplements vorhanden ?
7
  {    
8
    data[i] = data[i] + (currentData - 256);  // Subtraktion von der Gesamtsumme
9
  }
10
  else
11
    data[i] = data[i] + currentData;      // Addition zur Gesamtsumme
12
}

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?
#1343551
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).
Gast #1343563
Lesenswert?

Ich hab mir mal folgendes im Simulator angeguckt
1
  char foo = 0xFF;
2
  char bar = 100;
3
  PORTA = bar;
4
  bar += foo; //Ergebnis 99
5
  PORTB = bar;
6
  bar = bar + (foo - 256); //Ergebnix 98
7
  PORTC = bar;
Da sehe ich keinen unterschied, ob ich die negative Zahl einfach 
addiere, oder erst 256 abziehe.
#1343570
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
Gast #1343574
Lesenswert?

OK was ich auch seltsam finde ist folgendes:
1
  unsigned char foobar = 0xFF;
2
  char foo = foobar;
3
  short bar = 100;
4
  PORTA = bar>>8;
5
  bar += foo;
6
  PORTB = bar>>8;
7
  bar = bar + (foo - 256);
8
  PORTC = bar>>8;
PORTA -> 0x00
PORTB -> 0x01
PORTC -> 0x01

Wo kommen die Einsen her?
Gast #1343588
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
Gast #1343593
Lesenswert?

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

Wenn ich aber
1
  unsigned char foobar = 0xFF;
2
  char foo = foobar;
3
  short bar = 100;
4
  PORTA = bar&0xFF;
5
  bar += foo;
6
  PORTB = bar&0xFF;
7
  bar = bar + (foo - 256);
8
  PORTC = bar0xFF;
schreibe, dann passt es
PORTA -> 0x64
PORTB -> 0x63
PORTC -> 0x62
Gast #1343621
Lesenswert?

Meint ihr das sollte so funktionieren? (avr-gcc)
1
int16_t data[7];
2
int8_t currentData;
3

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

6
if(i != 0 && i < 3)  
7
{
8
  data[i] += currentData;
9
}
#1343634
Lesenswert?

martin schrieb:
> Meint ihr das sollte so funktionieren? (avr-gcc)
>
1
> int16_t data[7];
2
> int8_t currentData;
3
> 
4
> currentData = (int8_t)spi_read(); // spi_read gibt einen uint8_t zurück
5
> 
6
> if(i != 0 && i < 3)
7
> {
8
>   data[i] += currentData;
9
> }
10
>

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren