www.mikrocontroller.net

Forum: Compiler & IDEs C: Addition ohne Übertrag


Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Ich möchte in meinem Code gern eine einfache Prüfsumme über 3 Byte 
berechnen. Alles soweit kein Problem!

Aber jetzt kommts:  0xFF + 0x01 ist beim anschliesenden Test != 0x00 
wegen dem Carry.

Gibt es eine Möglichkeit in C ohne Übertrag zu addieren?


MfG Marc

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

Bewertung
0 lesenswert
nicht lesenswert
Marc schrieb:

> Aber jetzt kommts:  0xFF + 0x01 ist beim anschliesenden Test != 0x00
> wegen dem Carry.

sicher nicht wegen dem Carry.

Eher schon weil du die falschen Datentypen benutzt hast, bzw. dir die 
angewendeten C-Regeln nicht klar sind.

> Gibt es eine Möglichkeit in C ohne Übertrag zu addieren?

Zeig deinen Code.

Schuss ins Blaue: Deine Berechnung wird im Zahlenraum int durchgeführt, 
während du eigentlich unsigned char haben willst. Mit einem Cast sollte 
sich das Problem beheben lassen.

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Code geht leider grad nicht, bin nicht am Entwicklungsrechner.

Der Zahlenraum soll natürlich unsigned char sein. Ich habs mit uint8_t 
gemacht, was ja eigentlich stimmen müsste!?

Und es liegt am Carry, da im erzeugten ASM Code immer erst die normale 
Addition und dann nochmal die Carry-Addition durchgeführt wird. Beim 
anschliessenden Test zeigt der ASM Code, dass zwar das Ergebnis ==0x00 
ist, aber die Carryflags unterschiedlich sind und der Test somit negativ 
ist.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier funktionierts.

Ich glaub, du musst nochmal über Typenerweiterung nachdenken :->

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier der Code:

#include <avr/io.h>
#include <avr/interrupt.h> 
#include <stdint.h>
#include <util/delay.h>

#include "USI_TWI_Slave.h"

#define SLAVE_ADDRESS 0x10

uint8_t command, value, checksum;



void Process_Data(void)
{
  if((SLAVE_ADDRESS + command + value) == checksum)
  {
.
.
.


Wo funktionierts??

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich vermute, du speicherst die Prüfsumme nich in einer uint8_t Variable 
vor dem Vergleich, sondern machst den direkt. Berechnungen werden in C 
im Gültigkeitsbereich von int durchgeführt. Du könntest aber die unteren 
8 Bit mit einem binären UND maskieren.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Marc schrieb:
> Und es liegt am Carry, da im erzeugten ASM Code immer erst die normale
> Addition und dann nochmal die Carry-Addition durchgeführt wird. Beim

Also macht er die Karl-Heinz schon erwähnt hat die Berechnung auf 16-Bit 
Basis.
:-)

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und hier gleich mal noch der Assemblercode:
@00000030: Process_Data
45:       {
+00000030:   91400086    LDS       R20,0x0086     Load direct from data space
+00000032:   91800089    LDS       R24,0x0089     Load direct from data space
+00000034:   E090        LDI       R25,0x00       Load immediate
+00000035:   0F84        ADD       R24,R20        Add without carry
+00000036:   1D91        ADC       R25,R1         Add with carry
+00000037:   9640        ADIW      R24,0x10       Add immediate to word
+00000038:   91200088    LDS       R18,0x0088     Load direct from data space
+0000003A:   E030        LDI       R19,0x00       Load immediate
+0000003B:   1782        CP        R24,R18        Compare
+0000003C:   0793        CPC       R25,R19        Compare with carry
+0000003D:   F4F9        BRNE      PC+0x20        Branch if not equal

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Idiotensicher geklammert:
if ( ((uint8_t) (SLAVE_ADDRESS + command + value)) == checksum)

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Detlev T. schrieb:
> Ich vermute, du speicherst die Prüfsumme nich in einer uint8_t Variable
> vor dem Vergleich, sondern machst den direkt. Berechnungen werden in C
> im Gültigkeitsbereich von int durchgeführt. Du könntest aber die unteren
> 8 Bit mit einem binären UND maskieren.

Dem würde ich mich anschließen. Das nennt sich übrigens "integral 
promotion".
IAR hat einen schönen Beitrag über das Problem gemacht:

http://supp.iar.com/Support/?note=12582&from=searc...

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

Bewertung
0 lesenswert
nicht lesenswert
Marc schrieb:

>   if((SLAVE_ADDRESS + command + value) == checksum)

dir ist hoffentlich klar, dass der linke Teil (die Berechnung) als int 
Berechnung gemacht wird, laut C-Spezifikation

Damit wird auch der rechte Teil auf int hochgehoben und der Vergleich 
auch als int Vergleich gemacht.

> Und es liegt am Carry

Es liegt eben nicht am Carry. In C gibt es gar keinen Carry.
Es liegt daran, dass du fälschlicherweise annimmst, dass 2 unsigned char 
zusammenaddiert wieder einen unsigned char ergeben. Dem ist aber nicht 
so!

Berechnungen werden in C niemals in einem kleineren Datentyp als dem 
Datentyp int gemacht (*). In diesem Sinne sind
  if((SLAVE_ADDRESS + command + value) == checksum)

und
  uint8_t summ = SLAVE_ADDRESS + command + value;
  if(summ  == checksum)
    ...

2 völlig verschiedene Paar Schuhe!


(*) Es sei denn, der Optimizer kann beweisen, dass sich das Ergebnis 
nicht verändert, wenn er (bei einem 16 Bit int) das High-Byte ignoriert 
und nicht berechnet. Bei dir unterscheiden sich aber die Ergebnisse, 
daher muss die Berechnung als int-Berechnung gemacht werden.

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt ist mir alles klar! Vielen Dank für die Antworten! Wieder was 
gelernt :-)

Welche Variante erzeugt (vermutlich) weniger Code?
Die von Sven P. oder die von Karl Heinz?

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

Bewertung
0 lesenswert
nicht lesenswert
Marc schrieb:

> Welche Variante erzeugt (vermutlich) weniger Code?
> Die von Sven P. oder die von Karl Heinz?

Im Zweifelsfall im Assemblercode ansehen.
Bei aktiviertem Optimizer erwarte ich aber keinen Unterschied.

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok vielen Dank!

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eventuell ergibt das ja kürzeren Code:
uint8_t summ = SLAVE_ADDRESS;
  summ += command;
  summ += value;
  summ -= checksum;
  if(summ == 0)

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.