c avr ((1+2)*4 < -3)

Gast #6825470
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
Moderator Persönliche Seite #6825476
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?
#6825478
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.
Gast #6825488
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.
Moderator Persönliche Seite #6825489
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.
Gast #6825624
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);
Gast #6825727
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
#6825735
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.
Moderator #6825888
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)
Gast #6825950
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?
Gast #6825972
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.
Gast #6826247
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

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