Testen von Programmen wenn int < 32bit
-
Hallo,
Ich benutze den C++-Builder 2007, und wollte mein Programm unter "erschwerten" Bedingungen testen. Nämlich mit kleineren Variablen.
Ich habe fast nirgendsintverwendet sondern z.B.int16_t(also immer explizit die Größe mit angegeben) aber nachdem im RAM das Ganze in einem 32Bit Block (bei 32 bit-CPUs) gespeichert wird um Performance beizubehalten weiß ich nicht ob innerhalb einer Code-Zeile ein 16-Bit Überlauf aufgetreten ist (sondern eben nur 32-Bit Überläufe).
Wie kann ich das überprüfen? Bei den Optionen habe ich eine Einstellung 'Datenausrichtung' gefunden und die von 'Quad-Word' (warum 64Bit default?) auf 'Byte' umgestellt. Das Programm funktioniert weiterhin wie gewollt, allerdings traue ich dem nicht ganz. Kann mir jemand Tipps geben??LG
-
Du kannst jederzeit die beanspruchte Grösse eines Datentyps abfragen mit:
int size; size = sizeof(int)Damit bekommst du bei CBuilder Bytes.
-
cg07 schrieb:
Ich benutze den C++-Builder 2007, und wollte mein Programm unter "erschwerten" Bedingungen testen. Nämlich mit kleineren Variablen.
Das ist vertane Zeit. Es gilt sizeof(int) <= sizeof(long) <= sizeof(long long), int ist auf praktisch jedem gebräuchlichen 32-Bit-System auch 32 Bit groß, und bei späteren Compilergenerationen werden die Typen sicherlich nicht kleiner. Lediglich wenn du darüber nachdenkst, dein Programm mal nach 16-Bit-DOS oder auf einen Microcontroller zu portieren, kann das sinnvoll sein - aber dann ist die Integer-Größe sicherlich eines der kleineren Probleme.
cg07 schrieb:
Ich habe fast nirgends
intverwendet sondern z.B.int16_t(also immer explizit die Größe mit angegeben)Warum das? Die tatsächliche Bitgröße braucht man doch nur in seltensten Fällen.
cg07 schrieb:
aber nachdem im RAM das Ganze in einem 32Bit Block (bei 32 bit-CPUs) gespeichert wird um Performance beizubehalten weiß ich nicht ob innerhalb einer Code-Zeile ein 16-Bit Überlauf aufgetreten ist (sondern eben nur 32-Bit Überläufe).
Neinnein. Wenn du einen 16-Bit-Integer benutzt, wird auch mit 16-Bit-Registern gerechnet, und es treten auch 16-Bit-Überläufe auf. Desgleichen für alle anderen Typgrößen. Das ist ganz unabhängig davon, wie der Compiler die Daten im Speicher unterbringt.
cg07 schrieb:
Wie kann ich das überprüfen? Bei den Optionen habe ich eine Einstellung 'Datenausrichtung' gefunden und die von 'Quad-Word' (warum 64Bit default?) auf 'Byte' umgestellt.
Hat damit nichts zu tun. Die Datenausrichtung beeinflußt das Padding bei Klassen und Strukturen, also das Einfügen von Füll-Bytes, um Variablen zugunsten der Performance an möglichst "geradzahligen" Offsets stehen zu haben. Wenn du das auf "Byte" herunterstellst, werden deine Klassen und Strukturen möglicherweise etwas kleiner; dafür werden Speicherzugriffe oft ineffizienter.
(Die x86-Architektur ist eine der wenigen, die überhaupt Zugriffe auf nichtausgerichtete (D/Q)Words erlaubt. In vernünftigen Architekturen geht so etwas gar nicht.)
cg07 schrieb:
Kann mir jemand Tipps geben??
Widme dich produktiveren Dingen

-
@audacia: In früheren Zeiten war eine solche Frage schon wichtig. Man hatte als Compiler FORTRAN und die Grösse von INTEGER war durchaus unterschiedlich je nach Zielmaschine. Was auf dem eigenen System sauber lief konnte beim Anwender durchaus auf die Schnauze fliegen. Zum Glück ist das heute Vergangenheit oder wie andere das nennen ´Steinzeit der Programmierung´!

-
Die Frage ist immer noch aktuell, zumindest bei der Programmierung der eingebetteten Systeme, wo man Code von z.B. einem 16-Bit Mikrocontroller auf einen "32-Bitter" portieren möchte oder umgekehrt...
Ich kenne einen Fall, wo man zwei oder drei Wochen lang nach einem Fehler im FAT32-Dateisystem Treiber gesucht hatte. Das ganze lief auf einem 16-Bit Mikrocontroller und die Aufgabe des Mikrocontrollers bestand darin, Dateien von einem USB-Stick zu lesen. Ab und zu gab es Fehler bei fread() oder fopen(). Niemand wusste warum. Schließlich fand man im Treiber einen Ausdruck, wo jemand so viel wie möglich numerische Operationen mit einem Shift, Addition usw. in eine Zeile geschrieben hat, um einen Sektorindex o.ä. zu berechnen. Weiss nicht mehr, wie der Ausdruck ausgesehen hat, aber zusammengefasst war das so, dass sobald man einen INT32S (ein signed int) nach rechts geschoben hat, wurde das 15. Bit als Vorzeichenerweiterung benutzt, d.h. aus 0x00008000 wurde plötzlich 0xFFFF8000. Das ganze wurde dann nach INT32U (ein unsigned int) "gecastet" und es kamen dann falsche Zahlen heraus. Manchmal... aber der Fehler musste gefunden und gefixed werden und es gab viele Überstunden.
Seitdem gilt:
int ist Scheiße 
:xmas1:
-
audacia schrieb:
...Lediglich wenn du darüber nachdenkst, dein Programm mal nach 16-Bit-DOS oder auf einen Microcontroller zu portieren,...
Genau das mache ich. Nachdem allerdings mein AVR (8Bit) im Moment außer Reichweite ist, wollte ich das ganze quasi simulieren.
audacia schrieb:
Neinnein. Wenn du einen 16-Bit-Integer benutzt, wird auch mit 16-Bit-Registern gerechnet, und es treten auch 16-Bit-Überläufe auf. Desgleichen für alle anderen Typgrößen. Das ist ganz unabhängig davon, wie der Compiler die Daten im Speicher unterbringt.
Gibt es auf 32Bit CPUs 16-Bit Register???
LG
-
cg07 schrieb:
audacia schrieb:
...Lediglich wenn du darüber nachdenkst, dein Programm mal nach 16-Bit-DOS oder auf einen Microcontroller zu portieren,...
Genau das mache ich. Nachdem allerdings mein AVR (8Bit) im Moment außer Reichweite ist, wollte ich das ganze quasi simulieren.
audacia schrieb:
Neinnein. Wenn du einen 16-Bit-Integer benutzt, wird auch mit 16-Bit-Registern gerechnet, und es treten auch 16-Bit-Überläufe auf. Desgleichen für alle anderen Typgrößen. Das ist ganz unabhängig davon, wie der Compiler die Daten im Speicher unterbringt.
Gibt es auf 32Bit CPUs 16-Bit Register???
LG
Teilregister
http://www.c-plusplus.net/forum/38545
-
berniebutt schrieb:
@audacia: In früheren Zeiten war eine solche Frage schon wichtig. Man hatte als Compiler FORTRAN und die Grösse von INTEGER war durchaus unterschiedlich je nach Zielmaschine.
Schon klar. Ich habe in der Vergangenheit selbst einige Zeit damit verbracht, ein C-Programm zugleich auf einem 80186 (16 Bit, Little Endian) und einem 68k (32 Bit, Big Endian) zum Laufen zu bringen...
cg07 schrieb:
audacia schrieb:
...Lediglich wenn du darüber nachdenkst, dein Programm mal nach 16-Bit-DOS oder auf einen Microcontroller zu portieren,...
Genau das mache ich. Nachdem allerdings mein AVR (8Bit) im Moment außer Reichweite ist, wollte ich das ganze quasi simulieren.
Ah, okay, das ist natürlich etwas anderes.
Wenn du explizite Integergrößen verwendest (int16_t), sollte sich so auch das Überlaufverhalten korrekt simulieren lassen.
Edit: typographische Uneinheitlichkeit beseitigt
-
Das Problem ist, dass das anscheindend nicht funktioniert.
Folgender Code liefert nämlich nicht wie erwartet/erhofft 21844, sondern 43690 (Optimierung ist deaktiviert). Auch das ändern der Datenausrichtung ändert nichts.uint16_t x = 65535; uint16_t y = 2; uint16_t z = 3; uint16_t f = ((uint16_t)x*y)/z;allerdings liefert dieser Code das erwartete Ergebnis (21844)
uint16_t x = 65535; uint16_t y = 2; uint16_t z = 3; uint16_t f = x*y; f /= z;Somit kann ich meine Funktionen nicht wie gewünscht testen.
Den Grund verrät auch der asm-Code:#uint16_t x = 65535; 00407C56 66C745CEFFFF mov word ptr [ebp-$32],$ffff #uint16_t y = 2; 00407C5C 66C745CC0200 mov word ptr [ebp-$34],$0002 #uint16_t z = 3; 00407C62 66C745CA0300 mov word ptr [ebp-$36],$0003 #uint16_t f = ((uint16_t)x*y)/z; 00407C68 0FB745CE movzx eax,[ebp-$32] 00407C6C 0FB755CC movzx edx,[ebp-$34] 00407C70 F7EA imul edx 00407C72 0FB74DCA movzx ecx,[ebp-$36] 00407C76 99 cdq 00407C77 F7F9 idiv ecx 00407C79 668945C8 mov [ebp-$38],axLeider weiß ich nicht wie/ob es möglich ist das zu ändern.
LG
-
cg07 schrieb:
Das Problem ist, dass das anscheindend nicht funktioniert.
Folgender Code liefert nämlich nicht wie erwartet/erhofft 21844, sondern 43690 (Optimierung ist deaktiviert).[...]
Den Grund verrät auch der asm-Code:
[...]Das war mir nicht klar. Ist natürlich ärgerlich. Ob das wohl standardkonform ist?
Jedenfalls solltest du dir abhelfen können, indem du deinen eigenen int16_t-Typen definierst, der per Operatorüberladung die entsprechenden ASM-Befehle benutzt. Maximal effizient wird das zwar nicht sein (BCC kann Inline-Assembler-Statements nicht inlinen), aber dir geht es ja um Korrektheit.