Forum: Compiler & IDEs Warum übersetzt GCC-Compiler so unterschiedlich?


von Maxim B. (max182)


Lesenswert?

Guten Tag,
ich habe eine Frage:

Ich kenne C bestimmt noch nicht genug tief, aber ich habe geglaubt, daß 
diese zwei Zeilen äquivalent sind:
1
if(freq_zaehler & (1<<15)) phase_index |= (1<<0);
und
1
if(freq_zaehler & 0x00008000) phase_index |= (1<<0);

Trotzdem bekomme ich unterschiedliches Assembler-Ergebnis:
1
    if(freq_zaehler & (1<<15)) phase_index |= (1<<0);
2
 lds  r20, 0x04C6  ; 0x8004c6 <freq_zaehler>
3
 lds  r21, 0x04C7  ; 0x8004c7 <freq_zaehler+0x1>
4
 lds  r22, 0x04C8  ; 0x8004c8 <freq_zaehler+0x2>
5
 lds  r23, 0x04C9  ; 0x8004c9 <freq_zaehler+0x3>
6
 eor  r20, r20
7
 andi  r21, 0x80  ; 128
8
 or  r20, r21
9
 or  r20, r22
10
 or  r20, r23
11
 breq  .+2        
12
 ori  r24, 0x01

und
1
    if(freq_zaehler & 0x00008000) phase_index |= (1<<0);
2
 lds  r20, 0x04C6  ; 0x8004c6 <freq_zaehler>
3
 lds  r21, 0x04C7  ; 0x8004c7 <freq_zaehler+0x1>
4
 lds  r22, 0x04C8  ; 0x8004c8 <freq_zaehler+0x2>
5
 lds  r23, 0x04C9  ; 0x8004c9 <freq_zaehler+0x3>
6
 sbrc  r21, 7
7
 ori  r24, 0x01

Woran liegt das?
freq_zaehler ist unsigned long, phase_index ist unsigned int,
Atmel AVR 8-bit GNU Toolchain 3.6.0.1734 (avr-gcc-5.4.0.exe), AVR Studio 
4.19

Vielen Dank im voraus für eine Erklärung.

von Jim M. (turboj)


Lesenswert?

Maxim B. schrieb:
> if(freq_zaehler & (1<<15)) phase_index |= (1<<0);

Vorsicht: Du schiebst hier die "1" ins Vorzeichenbit eines int. Das ist 
IIRC laut Standard undefiniertes Verhalten, Du wolltest hier eher sowas 
wie (1UL<<15) schreiben.

von Dr. Sommer (Gast)


Lesenswert?

Maxim B. schrieb:
> 0x00008000
Das ist ein long (32bit)

(1<<15) ist ein int.

Optimierungen sind eingeschaltet?

von Patrick R. (ohmann)


Lesenswert?

Maxim B. schrieb:
> Ich kenne C bestimmt noch nicht genug tief, aber ich habe geglaubt, daß
> diese zwei Zeilen äquivalent sind:if(freq_zaehler & (1<<15)) phase_index
> |= (1<<0);undif(freq_zaehler & 0x00008000) phase_index |= (1<<0);
> Trotzdem bekomme ich unterschiedliches Assembler-Ergebnis

Inhaltlich mögen die beiden Ausdrücke letztlich das gleiche Resultat 
bewirken, dennoch sind es ja verschiedene Ausdrücke und haben demnach 
einen verschiedenen Assembleroutput.

von Maxim B. (max182)


Lesenswert?

Dr. Sommer schrieb:
> Optimierungen sind eingeschaltet?

Selbstverständlich.

Aber nun kapiere ich: alles, was nicht anders definiert ist, betrachtet 
Compieler als int. Das habe ich vergessen.
Vielen Dank!

aber auch so wird nicht besser, komischerweise:
1
    if(freq_zaehler & ((unsigned long)(1<<15))) phase_index |= (1<<0);
2
 lds  r20, 0x04C6  ; 0x8004c6 <freq_zaehler>
3
 lds  r21, 0x04C7  ; 0x8004c7 <freq_zaehler+0x1>
4
 lds  r22, 0x04C8  ; 0x8004c8 <freq_zaehler+0x2>
5
 lds  r23, 0x04C9  ; 0x8004c9 <freq_zaehler+0x3>
6
 eor  r20, r20
7
 andi  r21, 0x80  ; 128
8
 or  r20, r21
9
 or  r20, r22
10
 or  r20, r23
11
 breq  .+2      
12
 ori  r24, 0x01

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Maxim B. schrieb:
> (unsigned long)(1<<15)

Du shifftest noch immer den int und erweiterst das unsichere Ergebnis 
auf long.

Jim M. schrieb:
> Du wolltest hier eher sowas
> wie (1UL<<15) schreiben.

von Maxim B. (max182)


Lesenswert?

Bisher hatte ich immer gleiche Ergebnis mit Varianten
1
#define bb 4
2
#define cc 3
3
a |= (1<<bb)|(1<<cc);
und
1
a |= 0x18;

Interessant... Nun weiß ich ein bißchen mehr über C.

von Maxim B. (max182)


Lesenswert?

Jim M. schrieb:
> Du wolltest hier eher sowas
> wie (1UL<<15) schreiben.

Stimmt!
1
if(freq_zaehler & (1UL<<15)) phase_index |= (1<<0);
2
 lds  r20, 0x04C6  ; 0x8004c6 <freq_zaehler>
3
 lds  r21, 0x04C7  ; 0x8004c7 <freq_zaehler+0x1>
4
 lds  r22, 0x04C8  ; 0x8004c8 <freq_zaehler+0x2>
5
 lds  r23, 0x04C9  ; 0x8004c9 <freq_zaehler+0x3>
6
 sbrc  r21, 7
7
 ori  r24, 0x01
Nun alles wie erwünscht!
Vielen Dank!

von Dr. Sommer (Gast)


Lesenswert?

Es ist sowieso deutlich besser es so zu machen:
1
static const uint32_t amask = (1UL << 4);
2
static const uint32_t bmask = (1UL << 3);
3
a |= (amask | bmask);
Man beachte dass der Typ von amask/bmask fix uint32_t ist; es kann hier 
keine Überraschungen geben. Noch besser ist:
1
static const uint32_t amask = (((uint32_t) 1) << 4);
2
static const uint32_t bmask = (((uint32_t) 1) << 3);
So hat der Integer immer die richtige Größe, und man muss nicht 
überlegen ob es jetzt ein (unsigned) int oder long sein muss. Portabel 
ist es so auch.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Der Ausdruck 1<<15 ist, wie von Jim bereits angemerkt, undefiniert. Der
GCC liefert dafür naheliegenderweise den signed-int-Wert 0x8000 = -32768
(was aber nicht garantiert ist). -32768 auf (unsigned) long erweitert
hat das Bitmuster 0xffff8000. Die if-Bedingung wird also immer dann
wahr, wenn in freq_zaehler mindestens eins der Bits 15 bis 31 gesetzt
ist. Das ist natürlich nicht das, was du erwartet hast.

: Bearbeitet durch Moderator
von Maxim B. (max182)


Lesenswert?

Vielen Dank für Ihre ausführliche Erklärungen!

Das ist ein Versuch, DDS mit einer 12 bit 480 Wort-Tabelle zu 
realisieren (480 kann man leicher als 512 auf 2,3,4,5,8,10,12,16 
dividieren, das macht Berechnungen für Tabelle leichter). Ich wollte 
wissen, ob das alles zeitlich mit akzeptabler Frequenz(z.B. 40 kHz) 
machbar ist. MK sollte noch ja etwas Zeit haben, um Befehle von außen zu 
nehmen.

Deshalb überprüfe ich das mit Simulator, um später keine bösen 
Überraschungen zu bekommen. Immerhin gibt es genug anderen 
Fehlerquellen.

Variablen für Frequenz werde ich als __uint24 benutzen, die können aber 
in Simulator nicht in Watch-Fenster gesehen werden, deshalb zuerst 
unsigned long.

Wahrscheinlich sollte ich für die Zukunft die Ausdrücke wie x & (1<<nn) 
nur für Register und Ports benutzen. Alles anderes mit direkten 
Konstanten.

: Bearbeitet durch User
von tictactoe (Gast)


Lesenswert?

Weil klugsch... soviel Spass macht:

Yalu X. schrieb:
> Der Ausdruck 1<<15 ist, wie von Jim bereits angemerkt, undefiniert.

C++14 erklärt von allen zuvor undefinierten Fällen genau diesen als 
definiert (den, bei dem 1 in das Vorzeichenbit geschoben wird).

von mh (Gast)


Lesenswert?

tictactoe schrieb:
> Weil klugsch... soviel Spass macht:
>
> Yalu X. schrieb:
>> Der Ausdruck 1<<15 ist, wie von Jim bereits angemerkt, undefiniert.
>
> C++14 erklärt von allen zuvor undefinierten Fällen genau diesen als
> definiert (den, bei dem 1 in das Vorzeichenbit geschoben wird).

Vielen dank fürs klugsch... (ernsthaft)! Kannst du angeben wo genau es 
im Standard definiert wird (bin zu faul zum Suchen ;-) )

von Kaj (Gast)


Lesenswert?

tictactoe schrieb:
> C++14 erklärt
Hier geht es aber nicht um C++ sondernm laut TO, um C

von tictactoe (Gast)


Lesenswert?

mh schrieb:
> tictactoe schrieb:
>> Weil klugsch... soviel Spass macht:
>>
>> Yalu X. schrieb:
>>> Der Ausdruck 1<<15 ist, wie von Jim bereits angemerkt, undefiniert.
>>
>> C++14 erklärt von allen zuvor undefinierten Fällen genau diesen als
>> definiert (den, bei dem 1 in das Vorzeichenbit geschoben wird).
>
> Vielen dank fürs klugsch... (ernsthaft)! Kannst du angeben wo genau es
> im Standard definiert wird (bin zu faul zum Suchen ;-) )

Hier: http://www.eel.is/c++draft/expr.shift#2.sentence-3 (aka 8.5.7p2) 
oder auch hier: 
http://en.cppreference.com/w/cpp/language/operator_arithmetic Abschnitt 
Bitwise shift operators.

von Maxim B. (max182)


Lesenswert?

tictactoe schrieb:
> Hier: http://www.eel.is/c++draft/expr.shift#2.sentence-3 (aka 8.5.7p2)
> oder auch hier:
> http://en.cppreference.com/w/cpp/language/operator_arithmetic Abschnitt
> Bitwise shift operators.

Das ist aber kein C, sondern CPP.

Übrigens, ich habe nun Header für STM32 angekuckt: dort kann man 
Ausdruck (1UL<<n) treffen.

: Bearbeitet durch User
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.