Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Cardinal bzw. DWord und Integer mischen


Gausi - Mo 20.08.12 21:44
Titel: Cardinal bzw. DWord und Integer mischen
Ich hab da mal wieder eine Frage, an der man merkt, dass ich so'n Kram nicht gelernt hab. :mrgreen:

Ich habe einen TStream, in dem ich eine Reihe von DWords um einen bestimmten Wert ändern muss (vergrößern oder verkleinern). Das probier ich erstmal so (Effizienz bzgl. der Streamoperationen mal auslassen. Das geht vermutlich schneller, wenn ich erst alles in ein Array of DWord einlese, verändere, und dann zurückschreibe):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure fFixAudioOffsets(st: TStream; diff: Integer);
var v: Dword;
   // ...
begin
    // ...
    for i := 1 to Anzahl do
    begin
        st.Read(v, 4);               // Wert lesen
        v := ChangeEndian32(v);      // Dateiformat nutzt BigEndian, hier passiert ein  bswap EAX
        st.Seek(-4, soFromCurrent);  // zurückspringen

        v := v + diff;               // ändern        
        v := ChangeEndian32(v);
        st.Write(v, 4);              // schreiben
    end;


Dabei kommt natürlich in Zeile 12 eine Warnung bzgl. vorzeichenlose Typen blablub.

Wie macht man sowas richtig? So?


Delphi-Quelltext
1:
2:
3:
4:
5:
if diff >= 0 then
  v := v + DWord(diff)
else
  v := v - DWord(abs(diff));
end;


Edit: Titel ergänzt.


jaenicke - Mo 20.08.12 21:54

// EDIT:
Sorry, ist schon spät. :oops: Hab mich vertan.

Casten kannst du einen Cardinal ruhig in einen DWord, wenn du 100% sicher bist, dass der Wert darin nicht zu groß wird. (Denn sonst hättest du ja aufgrund der internen Darstellung plötzlich negative Zahlen.)
Ich würde da aber lieber ULONG bzw. LongWord nehmen, da Cardinal ein Metatyp ist, DWord aber nicht.


Gausi - Mo 20.08.12 22:01

Sind DWord und Cardinal nicht beides 32bit-Vorzeichenlose-Ganzzahltypen, also praktisch identisch? Das dachte ich zumindest immer. :gruebel:

[Edit] Es geht also um das Mischen von DWord mit Integer. ;-) [/Edit]

Und ja, die Werte sind immer so, dass man der Rechnung im gültigen Bereich liegt.


jaenicke - Mo 20.08.12 22:03

Ja, hab ich auch gerade realisiert. ;-)


Martok - Mo 20.08.12 22:10

Mach einfach das, was die Fehlermeldung auch sagt: Beide Operanden wurden erweitert.

Delphi-Quelltext
1:
Cardinal(Int64(v) + diff)                    


Ein "shut up and mov eax, diff; add v, eax" gibts leider nur in FPC; was gehen könnte (nicht getestet): inc(v, diff). Keine Ahnung, ob das geprüft wird...

Edit (da hier anscheinend alle hinterher editieren :mrgreen:): du kannst auch den Integer blind auf DWORD casten. Das gibt dann einen übergelaufenen dword, wenn der zum anderen addiert wird kommt dann der Grund ins Spiel warum 2's Complement für negative Werte verwendet wird und alles stimmt wieder ;)


Gausi - Mo 20.08.12 22:11

Ok, also geht das nur vernünftig über die Fallunterscheidung? Denn das erscheint mir etwas merkwürdig. :nixweiss:

Edit, ah, ok. Also erst das DWord auf Int64 bringen (Integer reicht ggf ja nicht), und dann hinterher wieder "kürzen"? Das mit inc probier ich auch mal, das sieht für mich ganz gut aus. :D

Einen (positiven) Integer in ein DWord casten sollte ja immer reibungslos gehen, und ebenso den Betrag eines negativen. Auf einen Bereichsüberlauf bei der Addition/Subtraktion lass ich es einfach drauf ankommen. Dann ist das neu getaggte 4GB-File halt kaputt. :mrgreen: