Problem bei 32-Bit-Addition

OP #2752546
Lesenswert?

Hi,

ich bin gerade mit meine Latein am Ende. Folgendes Problem:

Ich möchte 2 32bit integer addieren.
Die Funktion, welche die Rechnung enthält soll in einer statischen 
Bibliothek eingebunden werden.
In meinem Hauptprojekt will ich diese verwenden.

Das Problem: Das Ergebnis der Addition ist nonsense.
objdump verrät mir eine Zeile:
1
0e 94 00 00   call  0  ; 0x0 <mulkD>

Wenn ich nur die Funktion kopiere und in meinen Hauptprojekt 
(Contiki-Programm) kompiliere, erhalte ich das für mich sinvollere 
Ergebnis
1
0e 94 79 47   call  0x8ef2  ; 0x8ef2 <__mulsi3>

Was mache ich im ersten Teil falsch? Irgendein compiler-flag?

Vielen Dank schonmal.
OP #2752715
Lesenswert?

Aufrührend. AVR (ATmega1284p)

Vergisst man leider manchmal zu erwähnen, wenn man in seiner kleinen 
Welt gefangen ist.

Das Problem habe ich jetzt gelöst. Der angegebene Auszug ergibt sich 
wohl eher aus dem Linker.
Die Lösung des Problems war ein einfaches
1
-fno-strict-aliasing
 für den avr-gcc.

Die Problemstelle war eine Zuweisung eines long-Wertes an ein 2x-short 
array mittels pointer-casting.

Schematisch:
1
unsigned short xs[2];
2
*((long*)xs) = long_value;
Gast #2752988
Lesenswert?

Sowas löst man Standardkonform mit einer Union, so dass keine speziellen 
Compiler-Flags mehr nötig sind:
1
union {
2
    long val32;
3
    short val16[2];
4
} result;
5

6
result.val32 = a*b;
7

8
printf("%d, %d\n", result.val16[0], result.val16[1]);
Persönliche Seite #2753146
Lesenswert?

Sam P. schrieb:
> Sowas löst man Standardkonform mit einer Union, so dass keine speziellen
> Compiler-Flags mehr nötig sind:
>
1
> union {
2
>     long val32;
3
>     short val16[2];
4
> } result;
5
> 
6
> result.val32 = a*b;
7
> 
8
> printf("%d, %d\n", result.val16[0], result.val16[1]);

Was aber auch nicht standardkonform ist :-)

Der Standard sichert nur zu, daß die Komponente, die als letztes 
geschrieben wurde, beim Lesen diesen Wert liefert.

In deinem Fall ist der Wert von result.val16[] undefiniert.

Als Spracherweiterung sichert GCC zu, daß type punning funktioniert. 
Obiger Code geht also mit GCC, aber nicht unbedingt mit anderen 
Compilern.

Siehe auch "Casting does not work as expected when optimization is 
turned on" in http://gcc.gnu.org/bugs/#nonbugs

Neben Type-Punning sind natürlich auch die Aliasing-Regeln von C zu 
beachten: Ein short* ist kein Alias für ein long* oder umgekehrt. Wird 
also über ein long* geschrieben, kann der Compiler davon ausgehen, daß 
alles, was der über ein short* bereits kennt, sich dadurch nicht ändert.
Gast #2753172
Lesenswert?

Peter II schrieb:
> dumm nur das denn auf little oder bigendian etwas anders rauskommt.

Das hat man mit type-punning genauso. Endian-unabhängig (und 
Standard-konform -- ich gestehe ein, was ich vorschlug ist nur 
"GCC-konform") geht sowas wohl nur mit Bitmanipulation, also sowas wie
1
val16high = (val32>>16)&0xffff;
2
val16low = val32&0xffff;

(abzüglich Details zu signed/unsigned und so, die man ggf. beachten 
muss)

Wenn der Compiler schlau genug ist, übersetzt er das auch in genau so 
effizienten Maschinencode wie mit type-punning oder union. Es ist nur 
leider etwas weniger offensichtlich, was die Zeilen bezwecken sollen.

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