wenn ich z.B. in C für einen Returnwert nur 2 feste Konstanten (OK, FEHLER
o.ä.) vorsehe, macht es dann Sinn, diesen Datentyp als "int" (32-bit) zu
deklarieren?
Spare ich WIRKLICH Speicherplatz auf einer 32-bit Intel-Linux-Maschine, wenn
ich das Teil als unsigned char (8-bit) ansetze? Meine Frage geht dahin, was
der Compiler speichermäßig wirklich dafür reserviert. Bis jetzt habe ich
solche Variable immer so klein wie möglich deklariert, frei nach dem Motto:
"Wenn ich nur von 1 bis 10 inkrementiere, brauche ich keinen 2^32 Zahlenraum
zu reservieren!"
Was meint ihr dazu?
--
Bitte beim Mailen NOSPAM entfernen
=> Danke
> wenn ich z.B. in C für einen Returnwert nur 2 feste Konstanten (OK, FEHLER
> o.ä.) vorsehe, macht es dann Sinn, diesen Datentyp als "int" (32-bit) zu
> deklarieren?
Nein, hier empfiehlt sich ein enum.
> Spare ich WIRKLICH Speicherplatz auf einer 32-bit
> Intel-Linux-Maschine, wenn ich das Teil als unsigned char (8-bit)
> ansetze?
Vermutlich nicht, kommt auf den Compiler an. Aber selbst wenn: die
Einsparung ist so laecherlich gering, dass ich wirklich keinen
Gedanken darauf verschwenden wuerde.
--
Falk
Nur wenn es sich dabei um ein Feld von 8-bit Elementen handelt.
Zum Beispiel wird bei der Deklarationsfolge
unsigned char flag;
int wert;
jeder vernünftige Compiler auf einer 32-bit Architektur die
Variable "wert" mindestens auf einem Vielfachen von 4 ausrichten,
d.h. mindestens drei Füllbytes zwischen "flag" und "wert" einfügen.
Du sparst bei so etwas also nicht nur keinen Speicher, sondern läufst
auch Gefahr, dass das Laden eines 8-bit-Wertes in ein 32-bit breites
Register mehr Code erfordert...
> Meine Frage geht dahin, was der Compiler speichermäßig wirklich
> dafür reserviert.
Lässt sich mit sizeof, offsetof bzw. "&next_var - &prev_var"
herausfinden.
> Bis jetzt habe ich solche Variable immer so klein wie möglich
> deklariert,
Always use int, unless you have a good reason.
--
Mögen die Schwingen des Koffeins in lichte Höhen tragen.
Ohne deine Antwort anzweifeln zu wollen, aber kannst du das erklaeren? Ich
verstehe nicht so richtig was du meinst (wahrscheinlich deswegen weil ich
nicht besonders viel Ahnung davon habe wie ein Compiler arbeitet).
Also wenns nicht zuviel Umstaende macht faend ichs gut wenn du das etwas
ausfuehren koenntest :-)
Danke
Flo
--
Those who desire to give up Freedom in order to gain Security,
will not have, nor do they deserve, either one. (T. Jefferson)
>Alexander Bartolich <alexander...@gmx.at> wrote:
>
>> Du sparst bei so etwas also nicht nur keinen Speicher, sondern läufst
>> auch Gefahr, dass das Laden eines 8-bit-Wertes in ein 32-bit breites
>> Register mehr Code erfordert...
>
>Ohne deine Antwort anzweifeln zu wollen, aber kannst du das erklaeren?
Mal auf die Schnelle und speziell fuer Intel:
Lade 32-Bit-Wert:
| mov eax, [Variable]
Und fertig.
Lade 8-Bit-Wert:
unsigned:
| mov al, [Variable]
| movzx eax, al
oder
| xor eax, eax
| mov al, [Variable]
signed:
| mov al, [Variable]
| movsx eax, al
oder
| mov al, [Variable]
| cbw
| cwde
mov{s|z}x war speziell auf dem 386er nicht allzu effizient,
mittlerweile hat sich das, glaube ich geaendert. Neuere Intels moegen
wechselnde Zugriffe auf den 8-Bit und den 32-Bit-Teil des Registers
gar nicht und cbw/cwde passen IIRC nicht so ganz in die
RISC-Emulation.
Unter genuegend denkbaren Umstaenden ist es also moeglich bis ziemlich
wahrscheinlich, dass man das, was man an Datengroesse spart, in einem
Vielfachen an Codegroesse hinzubekommt und der Code dazu noch weniger
schnell ist.
Auf anderen CPUs sieht das nicht unbedingt sehr anders aus.
Vinzent.
Hm, auch wenn ichs nicht 100% verstanden hab, danke fuer die Erklaerung.
.oO( Ich sollte schleunigst Assembler lernen... )
>Hm, auch wenn ichs nicht 100% verstanden hab, danke fuer die Erklaerung.
Bitte. Ich versuch's noch mal anders:
Es ist in den meisten Faellen relativ daemlich, nur ein Viertel Ei in
die Pfanne zu hauen, bloss weil es so weniger Platz darin verbraucht.
Der zusaetzliche Aufwand, die restlichen drei Viertel noch
aufbewahren/verarbeiten zu muessen ist zu gross (halbe Eierschale
zurueck in den Kuehlschrank? "Zwischenspeicherung" in Tasse? Herd noch
mal extra anschmeissen?).
Nachher will man die anderen drei Viertel ja doch noch essen. ;)
>.oO( Ich sollte schleunigst Assembler lernen... )
Das sowieso. Und sei es nur, um den Output des Compilers zumindest
rudimentaer zu verstehen.
Vinzent.
Ein sinnloses Beispiel, ohne Optimierung für i386 übersetzt.
$ cat a.c
int main() {
unsigned char c = 42;
unsigned u = c;
return u;
}
$ gcc -Wall a.c && objdump -d a.out | sed -ne '/main/,/ret/p'
080483d0 <main>:
80483d0: 55 push %ebp
80483d1: 89 e5 mov %esp,%ebp
80483d3: 83 ec 08 sub $0x8,%esp
80483d6: c6 45 ff 2a movb $0x2a,0xffffffff(%ebp)
80483da: 0f b6 45 ff movzbl 0xffffffff(%ebp),%eax
80483de: 89 45 f8 mov %eax,0xfffffff8(%ebp)
80483e1: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
80483e4: 89 c0 mov %eax,%eax
80483e6: c9 leave
80483e7: c3 ret
Mit "sub $0x8,%esp" wird am Stack Platz für lokale Variablen
reserviert. Wie man sieht sind das 8 Byte, nicht nur 5.
"movzbl 0xffffffff(%ebp),%eax" lädt den Wert von "c" in das Register
eax und führt dabei Erweiterung von 8 auf 32-bit durch. Dazu ist nur
eine Instruktion nötig.
"mov %eax,0xfffffff8(%ebp)" speichert den Wert von Register eax in
"u". Ebenfalls nur eine Instruktion, allerdings ist der Maschinen-
code dazu (89 45 f8 vs. 0f b6 45 ff) ein Byte kürzer.
Wäre "c" ebenfalls vom Typ unsigned, würde das Programm genauso
viel Platz am Stack brauchen, aber ein Byte weniger Code ausmachen...
--
Für Google, Tux und GPL!
danke für die recht gute Erklärung! Gibt es über sowas (Zusammemspiel
Programm/Prozessor und Compiler) irgendwo im Netz gute Erklärungen?
Tutorials? Wenn ihr was wisst ... bitte mal aufschreiben! Ist bestimmt für
viele interessant, welche sich damit bis jetzt noch nicht soooo intensiv
beschäftigt haben :-)
Gruß,
Stefan
> Mit "sub $0x8,%esp" wird am Stack Platz für lokale Variablen
> reserviert. Wie man sieht sind das 8 Byte, nicht nur 5.
Noch ein Nachtrag von mir:
Das gleiche gilt für Strukturen, die ebenfalls wenn irgend möglich
"aligned" abgelegt werden.
Oft kann man dies mit #pragma pack(n) beeinflussen, nur ist das nicht
sicher, wenn dann ist es nicht portabel und meist nicht effizient.
So durfte ich mal die "geniale" Implementierung eines Kollegen, der
("Kids: Don't try this at home!") einen empfangsseitigen
Kommunikations-Bytestrom als Struktur abgebildet hatte, diesen per
memcpy() füllte und dann auf die Struktur zugriff, debuggen, weil er
dies nicht portiert bekam (von Wintel zu einer RS/6000 unter AIX).
Er scheiterte:
1. es gibt kein packing unter dem Zielprozessor -> Füllbytes zwischen
den Strukturelementen, er las Müll.
2. da das Binärdaten waren, stimmte natürlich auch der byte-sex nicht
3. er versuchte dann per char* p einen Zeiger weiterzuschieben und dann
jeweils per cast auf z.B. int* zuzugreifen -> bus error, weil der
Prozessor auf nicht ausgerichtete Elemente gar nicht zugreifen kann (int
von einer ungeraden Adresse laden geht nicht, Intel macht da
prozessorintern Klimmzüge und straft dies nur durch verlängerte
Ausführungszeiten ab)
Ich habe den Krempel weggeworfen und ein paar Serialisierungsfunktionen
geschrieben -> portabel und einfach zu durchschauen.
Bernd
http://www.schweikhardt.net/wider-die-sinnmacher.html
# Spare ich WIRKLICH Speicherplatz auf einer 32-bit Intel-Linux-Maschine, wenn
# ich das Teil als unsigned char (8-bit) ansetze?
Warum beantwortest Du die Frage nicht empirisch selbst? Ist es so
schwierig den Code einmal so, einmal anders zu übersetzen und sich
das Ergebnis anzusehen?
# Was meint ihr dazu?
Du willst auf einer Maschine mit mehreren hundert Millionen bytes ein
paar einsparen? Schabst Du auch Mücken von der Frontscheibe, damit Dein
Auto schneller fährt?
Regards,
Jens
--
Jens Schweikhardt http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)
Das ist für viele völlig uninteressant, besonders diejenigen, die nicht
für die CPU du jour programmieren, sondern maschinenunabhängig. Und für
Greenhorns sogar gefährlich. Warum willst Du Code durch
Quelltextänderungen für eine CPU optimieren? Reicht es nicht, wenn Du
das dem Compiler überläßt? Wie würde es Dir gefallen, eines Tages
halbverwüsteten C Code "optimiert für Sparc v9" lesen und ändern zu
müssen?
Denk mal tief nach, was Du vordergründig erreichen willst und was Du Dir
dabei eigentlich antust.
>Das ist für viele völlig uninteressant, besonders diejenigen, die nicht
>für die CPU du jour programmieren, sondern maschinenunabhängig. Und für
>Greenhorns sogar gefährlich.
Gefaehrlich wird der Code von Greenhorns vor allem dann, wenn sie
genau gar keine Ahnung haben, was der Compiler aus ihrem Code macht.
Vinzent.