short int vs int Probleme

M

matzeed7

Mitglied
Hallo,

ich habe heute bemerkt das es zu einem Widerspruch bei einer
meiner Implemenrierungen kommt!

ich habe versucht die einzelnen Bit eines int auszugeben.
dazu habe ich mir eine kleines testfile geschrieben. Indem folgender code
vorkam:
Code:
unsigned int wert=0xfc;
 for(int i=0;i<32;i++){
		cout  <<((wert<<i)>>31 ) ;
 }

die ausgabe war wie von mir erwartet:
0000 0000 0000 0000 0000 0000 1111 1100

nun wollte ich, um a bissel platz zu sparen, das ganze auf unsigned short int
überführen was ja eine grösse von nur zwei byte ergibt, also habe ich die
31 in eine 15 umgetauscht, aber die ausgabe war nicht die die ich erwartete!!

Code:
unsigned short int test=0xfc;
	
	 for(int i=0;i<16;i++){
		cout  <<((test<<i)>>15 ) ;
         }
ausgabe: 00000000137153163126252

kann mir wer sagen wo mein fehler(denkfehler) liegt!!!

Danke schon mal im voraus
Gruss Matze
 
( Hast du schon versucht, das ganze zu casten? ) < Oo'

PS: Wenn's dir schon auf Geschwindigkeit ankommt, nimmt ASM oder nutze den Heap/Freispeicher (C++: new x| C: x = malloc())
 
Zuletzt bearbeitet:
Aeh... 0xfc ist 252. Jeder Linksshift halbiert die Zahl, darum ist die Ausgabe voellig korrekt (schreib hinter deine Ausgabe mal noch eine Newline, dann siehste die einzelnen Werte). In welcher Form du die Variable deklarierst, ist egal. So gesehen bringt das gar nichts.

Um eine Zahl in die Binaerdarstellung umzurechnen, muss man den Rest betrachten, der bei jeder Division durch 2 entsteht.

edit: Bleh, nicht richtig geschaut. Ich verweise dennoch auf meine Methode und zitiere meinen Prof: "Wenn sie so ueber den Code nachdenken muessen, dann ist es schlechter Code. Sowas schreiben Sie bitte nicht!"
 
Zuletzt bearbeitet:
muss man denn den rest beachten, wenn die zahlen schon binär abgelegt sind
also zb als doubleword oder so?
 
Zuletzt bearbeitet:
Was meinst du mit "binaer abgelegt"? Die Zahlen sind nur binaer, anders kann sie der Rechner doch gar nicht speichern. Ob du sie in deinem Quelltext nun binaer, oktal, dezimal oder hexadezimal schreibst, ist egal, das bastelt der Compiler um.
 
Durch den linksshift
Code:
(test<<i)
wird auf int(4 byte) gecastet.
Deshalb gehen die bits vor bin number i nicht verloren und werden mitausgegeben.
Vielleicht könntest du dich damit etwas spielen, aber das sind 2 Byte Stackspeicher sicher nicht wert!
 
Um die einzelnen bits zu testen, musst Du mit Binaeroperatoren arbeiten, etwa in der Art
Code:
for(int i = 0; i < sizeof(int); ++i)
{ 
  std::cout << (test & (1<<i)) << '|';
}
 
Hier nochmal in c aber c++ ist ja abwertskompatibel.
Code:
do 
{
        printf("%i", (test&1));
}while(test/=2);
Bei meiner version sparst du dir ram :)

Aber jetzt für die erfahreneren unter euch, machts einen unterschied, ob man in dem fall test&1 oder test%2 schreibt? Ich mein von performance gründen.

Ist das bit shiften bei (mid/high/low)endian überhaupt zulässig?
 
Ja, das macht einen Unterschied: Der &-Operator braucht nur eine Anweisung, die sehr wenig Takte benötigt: "and". Bei dem Modulo-Operator hängt das verwendete von den Optimierungen ab. Das "intuitivste" wäre die div-Instruktion, die jedoch eine ziemlich langsame(über 50 Takte) und im Vergleich wesentlich "kompliziertere" Operation ist, als ein simples "and eax,1".
Jedoch verwenden heute viele Kompiler die div-Anweisung nurnoch, wenn es gar nicht anders geht und Division und Reste werden bei konstantem Divisor meist durch "reciprocal multiplication"(~Mit dem Kehrwert multiplizieren) gelöst(Da man keine Kommazahlen hat ohne die FPU zu nutzen, greift man auf "fixed-point arithmetic" zurück, d.h. "man denkt sich" den Teil vor dem Komma in edx und den Komma-Anteil in eax). Das ist aber trotzdem noch aufwendiger. Zur Verdeutlichung hier einmal was gcc aus int x = y/3; macht:
Code:
8048335:       c7 45 f4 b3 15 00 00    mov    DWORD PTR [ebp-12],0x15b3
 804833c:       8b 45 f4                mov    eax,DWORD PTR [ebp-12]
 804833f:       89 45 e8                mov    DWORD PTR [ebp-24],eax
 8048342:       c7 45 e4 56 55 55 55    mov    DWORD PTR [ebp-28],0x55555556
 8048349:       8b 45 e4                mov    eax,DWORD PTR [ebp-28]
 804834c:       f7 6d e8                imul   DWORD PTR [ebp-24]
 804834f:       89 d1                   mov    ecx,edx
 8048351:       8b 45 e8                mov    eax,DWORD PTR [ebp-24]
 8048354:       c1 f8 1f                sar    eax,0x1f
 8048357:       89 ca                   mov    edx,ecx
 8048359:       29 c2                   sub    edx,eax
 804835b:       89 d0                   mov    eax,edx
 804835d:       89 45 f8                mov    DWORD PTR [ebp-8],eax

Aus dem selben Grund sollte man statt test/=2 auch lieber test>>=1 schreiben.(Es kann aber auch sein, dass der Kompiler das von selbst optimiert)

Edit: Ich habe gerade nochmal nachgeschaut: dpkg hat recht, test%2 wird von gcc durch ein and ersetzt, allerdings stehen noch eine Menge Operationen mehr drin als bei einem test&1:
(gcc-version: 4.2.0, keine extra Optionen beim kompilieren)
test%2:
Code:
804833c:       8b 55 f4                mov    edx,DWORD PTR [ebp-12]
804833f:       89 d0                   mov    eax,edx
8048341:       c1 f8 1f                sar    eax,0x1f
8048344:       89 c1                   mov    ecx,eax
8048346:       c1 e9 1f                shr    ecx,0x1f
8048349:       8d 04 0a                lea    eax,[edx+ecx]
804834c:       83 e0 01                and    eax,0x1
804834f:       29 c8                   sub    eax,ecx
8048351:       89 45 f8                mov    DWORD PTR [ebp-8],eax

test&1:
Code:
804833c:       8b 45 f4                mov    eax,DWORD PTR [ebp-12]
804833f:       83 e0 01                and    eax,0x1
8048342:       89 45 f8                mov    DWORD PTR [ebp-8],eax
 
Zuletzt bearbeitet:
marcellus schrieb:
Aber jetzt für die erfahreneren unter euch, machts einen unterschied, ob man in dem fall test&1 oder test%2 schreibt? Ich mein von performance gründen.

Ob du test&1 oder test%2 schreibst, sollte bei einem gutem Compiler( was der gcc ja ist ) egal sein.

marcellus schrieb:
Ist das bit shiften bei (mid/high/low)endian überhaupt zulässig?
Ja, denn high/low endian sagt nur etwas darüber aus, wie die zahl im arbeitsspeicher abgelegt ist, geshiftet wird aber sowieso im Register.
 
Ja, denn high/low endian sagt nur etwas darüber aus, wie die zahl im arbeitsspeicher abgelegt ist, geshiftet wird aber sowieso im Register.

[Haarspalterei] Es wird nicht immer im Register geshiftet:
Aus t>>=3 wird:[/Haarspalterei]
Code:
 sar    DWORD PTR [ebp-8],0x3

Aber dennoch kümmert sich der Prozessor um die Endianess und sorgt dafür, dass die Bits richtig verschoben werden, daher spielt es keine Rolle ob es sich um high oder low endian handelt.
 
Zuletzt bearbeitet:
@Lesco mit welcher option bekommt man den assembler output, ich hab das gcc manual durchgesehen, aber ich find das irgendwie nicht. Ich glaub das wär eine gute idee um zu schauen was schneller läuft.

Jede assembler zeile braucht einen Takt oder?
 
Ich zitiere "man gcc"
-S Stop after the stage of compilation proper; do not assemble. The
output is in the form of an assembler code file for each non-assem-
bler input file specified.

Jede assembler zeile braucht einen Takt oder?
Nein, jede Zeile stellt einen Befehl an die CPU dar und jeder Befehl besteht aus einer bestimmten Zahl an Takten. Dabei kommts auch auf die CPU an, bei CISC-CPUs gibt es sehr viele umfangreiche Befehle, die durchaus "einige Dutzend Takte" (wie mein Prof. immer zu sagen pflegte...) benoetigen.
 
auf -S bin ich gekommen, das hat aber nicht die form

Code:
804833c:       8b 55 f4                mov    edx,DWORD PTR [ebp-12]
804833f:       89 d0                   mov    eax,edx
8048341:       c1 f8 1f                sar    eax,0x1f
8048344:       89 c1                   mov    ecx,eax
8048346:       c1 e9 1f                shr    ecx,0x1f
8048349:       8d 04 0a                lea    eax,[edx+ecx]
804834c:       83 e0 01                and    eax,0x1
804834f:       29 c8                   sub    eax,ecx
8048351:       89 45 f8                mov    DWORD PTR [ebp-8],eax
(von Lesco)

Sondern von

http://rafb.net/p/zsZcWS71.html

auf

http://rafb.net/p/ynzuN591.html

Das ist für mich sogar noch schlechter ersichtlich als assembler ansich. Ich hab pic assembler in der schule gelernt, deswegen kenn ich wenigstens einen minimalanteil, aber mit meiner ausgabe fang ich nicht wirklich was an.
 
Haengt ja davon ab, fuer welchen Compiler das sein soll. Wenn der andere Auswurf mit gcc gemacht wurde, dann wirds noch andere Optionen geben, mit denen man das aendern kann, da bin ich jetzt auch ueberfragt.
 
versuch mal

gcc -S test.c -dP

und dann in der test.s

sieht man wie die RTL Zwischendarstellung,
in der virt/pseudoregister auf die As-Instruction abgebildet werden
 
Also die Darstellung die ich gepostet habe stammt von objdump -M intel -d <datei>. Die entsprechenden gcc-Flags kannte ich vorher noch nicht, aber gut zu wissen.
 
die frage ist ob man diese braucht,
für die allgemeinbilde/interesse aber gut zu wissen, was alles möglich ist

so kann man sich auch gut die einzelnen schritte der optimierungstufen/ pässe des gcc ansehen für mich war das schon sehr interessant, zu wissen
wie es vom frontend über die RTL zwischensprache und dann zum backend kommt
 

Ähnliche Themen

Modulfehler?

Festplatte friert ein nach suspend/resume

Displayport + externer Monitor zeigt bei startx nichts erst bei DVI

Festplatte stirbt, dd funktioniert nicht

Textkonsole mit KMS zu klein

Zurück
Oben