Forum: Mikrocontroller und Digitale Elektronik c avr ((1+2)*4 < -3)


von Simon (Gast)


Lesenswert?

folgendes kleines Testprogramm kommt, meiner Meinung nach, zu einenm 
falschen Ergebnis.
Kann mir bitte jemand erklären was hier passiert?
1
volatile int16_t a,b,c;
2
volatile uint16_t d;
3
volatile int8_t erg;
4
5
a = 1;
6
b = 2;
7
c = -3;
8
d = 4;
9
10
if ((a+b)*d > c)
11
{
12
  erg = 1;
13
}
14
else if ((a+b)*d < c)
15
{
16
  erg = -1;
17
}
18
else
19
{
20
  erg = 0;
21
}

erg hat den Wert -1.

Herzlichen Dank,
Simon

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Simon schrieb:
> folgendes kleines Testprogramm kommt, meiner Meinung nach, zu einenm
> falschen Ergebnis.

Welcher Compiler, welche Version, welche Compileroptionen?

> erg hat den Wert -1.

Wie hast Du diesen auf einem AVR ausgeben lassen?

P.S.

Ich glaube das persönlich nicht, der Fehler muss woanders liegen.

P.P.S

Alle Variablen sind volatile deklariert, d.h. Du teilst dem Compiler 
mit, dass sie an anderer Stelle (z.B. in einer ISR) beliebig abgeändert 
werden könnten. Ist das Absicht? Meines Erachtens ist Dein Mini-Programm 
nur die halbe Wahrheit.

Kannst Du das tatsächlich mit diesem Progrämmchen auf einem AVR 
reproduzieren oder hast Du das eigentliche Programm so weit vereinfacht, 
dass hier komplett der Kontext (und auch der Fehler) verlorengegangen 
ist?

: Bearbeitet durch Moderator
von Adam P. (adamap)


Lesenswert?

Frank M. schrieb:
> Ich glaube das persönlich nicht, der Fehler muss woanders liegen.

Ist so, hab mich grad auch gewundert.
Ich habs mal auf die schnelle mit Arduino getestet (ATmega2560).

Jedoch gibt es eine Warning:
"warning: comparison between signed and unsigned integer expressions 
[-Wsign-compare]"

Beim AtmelStudio mit einem Cortex-M4 funktioniert es richtig.

: Bearbeitet durch User
von my2ct (Gast)


Lesenswert?

Simon schrieb:
> Kann mir bitte jemand erklären was hier passiert?

Du verrechnest Äpfel mit Birnen und verlässt dich dabei auf implizite 
Typumwandlungen.

von Adam P. (adamap)


Lesenswert?

my2ct schrieb:
> Du verrechnest Äpfel mit Birnen und verlässt dich dabei auf implizite
> Typumwandlungen.

Ja, sehe ich auch so, denn so funktioniert es, was natürlich auch 
logisch ist:
1
if ((int16_t)((a+b)*d) > c)

von Bitkaspar (Gast)


Lesenswert?

Schaut dir einfach mal die Binärcodierung von -3 an und wie der 
maschinenbefehl CMP funktioniert.

Zu erinnerung CPU-Register kennen keine Unterschied zwischen signed und 
unsigned, die vergleichen stur die Bits.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Adam P. schrieb:
> Jedoch gibt es eine Warning:
> "warning: comparison between signed and unsigned integer expressions
> [-Wsign-compare]"

Ich habs eben unter Linux getestet. Bei mir gibt es weder diese Warnung 
noch den Fehler: Es wird "1" ausgegeben.
1
$ cc -O2 -Wall -Wextra a.c
2
$ ./a.out
3
1
4
$ cc -v
5
...
6
gcc version 8.3.0 (Debian 8.3.0-6)
Wenn, dann muss es etwas avr-gcc-spezifisches sein - eventuell in einer 
speziellen Compilerversion.

: Bearbeitet durch Moderator
von Simon (Gast)


Lesenswert?

my2ct schrieb:
> Du verrechnest Äpfel mit Birnen und verlässt dich dabei auf implizite
> Typumwandlungen.

Richtig, darauf hatte ich mich verlassen.
Ich dachte ein Vorzeichen auf jeder Seite sollte reichen.

von Johannes S. (Gast)


Lesenswert?


von Peter D. (peda)


Lesenswert?

Simon schrieb:
> erg hat den Wert -1.

Das ist korrekt. Der Vergleich erfolgt im größeren Format und das ist 
auf nem 8Bitter uint16_t.
Aus -3 wird somit 0xFFFD = 65533
Und 12 < 65533

Auf nem 32Bitter ist aber int > uint16_t, da int == int32_t.

von EAF (Gast)


Lesenswert?

Bestätige:

Sehe die Warnung auch auf AVR und es kommt -1 raus.
Die Warnung ist also mehr als berechtigt.

Bei RP2040 und STM32 zeigt sich 1 ohne Warnung.

von Simon (Gast)


Lesenswert?

Vielen Dank, bei der Aktivierung -Wextra gibt es bei mir auch eine 
Warnung.
Nun habei ich noch ein anderes Problem, vielleicht könnt ihr mir da auch 
helfen:
Folgender Code liefert die Warnung:
signed and unsigned type in conditional expression
Kann ich das Problem besser lösen?
1
#define BV(bit) (1 << (bit))
2
#define bit_is_high(reg,bit)  (((reg)&BV(bit))!=0)
3
#define vorzeichen_erweitern(x) (bit_is_high(x, 9) ? x | 0xFC00 : x)
4
int16 tmp = ADC;
5
tmp = vorzeichen_erweitern(tmp);

von Simon (Gast)


Lesenswert?

ps.: Ganz vergessen.
Der ADC liefert einen vorzeichenbehafteten 12Bit-Wert.

von A. S. (Gast)


Lesenswert?

Simon schrieb:
> signed and unsigned type in conditional expression
> Kann ich das Problem besser lösen?

Naja, entweder signed oder unsigned rechnen oder casten.

Ein ganz brauner "Trick": linksshiften um 6 und danach rechtsschiften 
genauso viel. Dann brauchst Du kein If und keine defineorgien.

int16 tmp = ADC<<6;
tmp>>=6;

Bzw 3 bei typischen 12 Bit + Vorzeichen

von Klaus W. (mfgkw)


Lesenswert?

Simon schrieb:
> Kann ich das Problem besser lösen?

Jedenfalls nicht mit Makros.
Seit den 80ern sind schon ein paar Jahre ins Land gegangen.

Ansonsten halt mit cast ausdrücken, was man wie konvertiert haben will 
anstatt es dem Compiler zu überlassen: will ich bei einem Vergleich 
eines signed mit einem unsigned den Vergleich in signed oder in unsigned 
haben? Entsprechend das eine oder andere konvertieren.

von Nop (Gast)


Lesenswert?

Simon schrieb:

> Kann mir bitte jemand erklären was hier passiert?

Eselsbrücke: unsigned ist ansteckend.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Simon schrieb:
> Kann ich das Problem besser lösen?

Ersetze
1
x | 0xFC00

durch
1
x - (1 << 10)

Das gibt keine Warnung, weil alles in signed gerechnet wird, und
funktioniert auch, wenn x bzw. tmp mehr als 16 Bit breit ist.

Simon schrieb:
> ps.: Ganz vergessen.
> Der ADC liefert einen vorzeichenbehafteten 12Bit-Wert.

Sicher? bit_is_high(x, 9) und 0xFC00 sehen für mich eher nach 10 Bit
aus. Für 12 Bit wäre die Ersatzschreibweise
1
x - (1 << 12)

: Bearbeitet durch Moderator
von jemand (Gast)


Lesenswert?

Frank M. schrieb:
> Adam P. schrieb:
>
>> Jedoch gibt es eine Warning:
>> "warning: comparison between signed and unsigned integer expressions
>> [-Wsign-compare]"
>
> Ich habs eben unter Linux getestet. Bei mir gibt es weder diese Warnung
> noch den Fehler: Es wird "1" ausgegeben.
> $ cc -O2 -Wall -Wextra a.c
> $ ./a.out
> 1
> $ cc -v
> ...
> gcc version 8.3.0 (Debian 8.3.0-6)
>
> Wenn, dann muss es etwas avr-gcc-spezifisches sein - eventuell in einer
> speziellen Compilerversion.

Ich würde es auf die integer Promotion schieben: bei arithmetischen 
Operationen werden die Operanten implizit auf int gecastet, sofern ihr 
Typ schmaler ist als int.
Auf den 32bit MCUs und dem PC ist das gegeben, auf dem AVR nicht.
Warum unsigned signed auf dem AVR „Vorrang“ gegeben wird, weiß ich 
nicht, vielleicht ist es UB/IDB und deswegen die Warnung?

von jemand (Gast)


Lesenswert?

Kleine Ergänzung: dass unsigned der Vorrang gewährt wird, ist hier 
dokumentiert: 
https://en.cppreference.com/w/cpp/language/operator_arithmetic
Advent also Teil des Standards zu sein.

von Bitkaspar (Gast)


Lesenswert?

Simon schrieb:
> Der ADC liefert einen vorzeichenbehafteten 12Bit-Wert.

Welcher ADC?
Bei einigen ADC's kann man konfigurieren was man braucht:
-binary
-binary offset
-2 complement
-gray
-1 complement

eine 'Vorzeichenbehaftete Codierung (signed) gibt es genau genommen bei 
ADC's nicht, das heisst höchstens 'polar encoding', weil dem ADC ist es 
wurscht wo du den 0-Punkt in das Analogintervall Min-Max  setzt. Dem 
C-Compiler dagegen nicht.

von Simon (Gast)


Lesenswert?

Yalu X. schrieb:
> Das gibt keine Warnung, weil alles in signed gerechnet wird, und
> funktioniert auch, wenn x bzw. tmp mehr als 16 Bit breit ist.
>
> Simon schrieb:
>> ps.: Ganz vergessen.
>> Der ADC liefert einen vorzeichenbehafteten 12Bit-Wert.
>
> Sicher? bit_is_high(x, 9) und 0xFC00 sehen für mich eher nach 10 Bit
> aus. Für 12 Bit wäre die Ersatzschreibweise

Herzlichen Dank!
Du hast natürlich Recht; es ist ein 10 Biit ADC.

Gruß
Simon

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.