Bitverschiebung - Portierung von Assembler in C++



  • Habe die Suchfunktion schon genutzt und nichts passendes zu meinem Problem gefunden.

    Ich versuche gerade die Bitverschiebungsfunktion SHRD in C++ zu portieren
    Leider funkioniert diese bis jetzt nur bei postiven Zahlen.

    Erstmal die Beschreibung von SHRD:
    "Der SHRD-Befehl bewirkt, daß die Bits im Zieloperanten um x Positionen nach rechts
    verschoben werden und die höherwertigen Bits vom 2. Operanten nachgeschoben (aufgefüllt)
    werden"

    Hier meine Code (geht bestimmt auch effektiver - aber naja !)

    Aufruf:

    AnsiString bin1, bin2, bin3, bin4;
    	int eax, edx, RESULT;
    
        	//eax (32bit) in Binär wandeln
        	Int2Bin(eax, 32, &strbin);
        	bin1 = strbin;
    
        	//edx (32bit) in Binär wandeln
        	Int2Bin(edx, 32, &strbin);
        	bin2 = strbin;
    
        	bin3 = bin2 + bin1;
    
        	bin4 = bin3.SubString(bin1.Length() - 0x1e + 1, bin1.Length());
    
        	Bin2Int(bin4, &iVal);
    
    	RESULT = iVal;
    

    Funktionen:

    void Int2Bin(__int64 value, int iBit, AnsiString *strBin)
    {
        	//Variablendeklaration
        	int arraybin[255], i = 0;
        	__int64 temp1 = 0, temp2 = 0;
        	AnsiString bin;
    
        	temp1 = value;
    
    	//in Binär wandeln
        	while(temp1 > 0)
        	{
            	temp2 = fmodl(temp1, 2);
            	arraybin[i] = temp2;
            	temp1 = temp1 / 2;
            	i++;
        	}
    
        	//mit Nullen auf die Anzahl der Bits auffüllen
        	if(i < iBit)
        	{
            	for(i; i < iBit; i++)
            	{
                		arraybin[i] = 0;
            	}
        	}
    
        	i--;
    
        	//in richtige Reihenfolge bringen
        	for(i; i > -1; i--)
            	bin = bin + arraybin[i];
    
        	//Rückgabewert füllen
        	*strBin = bin;
    }
    //----------------------------------------------------------------------
    
    void Bin2Int(AnsiString strBin, __int64 *value)
    {
        	//Variablendeklaration
        	int k = 0;
        	__int64 temp1 = 0, temp2 = 0;
        	int arraybin[255];
        	AnsiString tempstr;
    
        	for(k; k < strBin.Length(); k++)
        	{
            	tempstr = strBin.SubString(strBin.Length() - k, 1);
    
            	if(tempstr.ToInt() != 0)
            	{
                		temp1 = tempstr.ToInt() * pow(2, k);
                		temp2 = temp2 + temp1;
            	}
        	}
    
        	//Rückgabewert füllen
        	*value = temp2;
    }
    //----------------------------------------------------------------------
    

    Das erste Beispiel mit zwei postiven Zahlen bringt auch das gewünschte Ergebnis

    eax = 159976EA (dez. 362378986)
    edx = 086F00E7 (dez. 141492455)
    cl = 1E (dez. 30)

    Schiebeoperation shrd eax,edx,cl (shrd 159976EA,086F00E7,1e)
    eax = 0001 0101 1001 1001 0111 0110 1110 1010
    edx = 0000 1000 0110 1111 0000 0000 1110 0111

    edx (höherwertig-32bit)+eax (niederwertig-32bit)
    0000 1000 0110 1111 0000 0000 1110 0111 0001 0101 1001 1001 0111 0110 1110 1010

    0010 0001 1011 1100 0000 0011 1001 1100 (per Hand verschoben & mit eigener Funktion)

    Rückgabewert = 21BC039C (richtig !!!)

    Bei diesen Zahlen gibt's aber das Problem

    eax = f00e7159 (dez. -267488935 !!!!!!!!!!!!)
    edx = 08316a6e (dez. 137456238)
    cl = 1E (dez. 30)

    Schiebeoperation shrd eax,edx,cl (shrd f00e7159,08316a6e,1e)
    eax = 0000 1111 1111 0001 1000 1110 1010 0111
    edx = 0000 1000 0011 0001 0110 1010 0110 1110

    edx (höherwertig-32bit)+eax (niederwertig-32bit)
    0000 1000 0011 0001 0110 1010 0110 1110 0000 1111 1111 0001 1000 1110 1010 0111

    0010 0000 1100 0101 1010 1001 1011 1000 (per Hand verschoben = 20c5a9b8)
    0010 0000 1100 0101 1010 1001 1011 1011 (Ergebnis muss rauskommen = 20c5a9bb !!!!)

    wo kommen die letzten zwei Einsen beim richtigen Ergebnis her ????
    (Das richtige Ergebnis gibt die SHRD-Funktion in einem Assemblerprogramm zurück
    - ist also definitiv richtig)

    es wird sicher damit zusammenhängen das eax negativ ist.
    Zitat:
    "Das höchtswertige Bit einer Zahl wird zur Darstellung des Vorzeichens verwendet."

    das höchstwertige Bit von eax ist doch aber eine von 0.
    Welches Bit soll gemeint sein und wie kann ich aus einer negativen Zahl eine positive
    machen ??

    Hab es auch mal mit Inline-Assembler versucht - da hagelte es aber Fehlermeldungen

    int RESULT;
    
    _asm
    {
    mox cl,1E
    mov edx,08316A6E
    mov eax,F00E7159
    shrd eax,edx,cl
    }
    
    RESULT = eax;
    

    müsste doch so langen - oder ????? (hab noch nicht mit Inline-Asm gemacht !!!)



  • skinny schrieb:

    Hab es auch mal mit Inline-Assembler versucht - da hagelte es aber Fehlermeldungen.

    Was denn für welche?

    Hüftschuss von mir:

    [cpp]
    int iResult;

    _asm
    {
    mox cl,1E
    mov edx,08316A6E
    mov eax,F00E7159
    shrd eax,edx,cl
    mov iResult, eax
    }
    [/cpp]



  • Jo, der Inline Assembler funtzt jetzt.
    Danke für den kleinen Tip!

    Das richtige Ergebnis 20c5a9bb (hex) wird nun auch zurückgegeben.
    Aber leider in meiner C++ Funktion nicht (Wieso ???)

    Die Fehlermeldungen beim Inline Assembler kommen, wenn ich die Werte
    nicht direkt sondern über Variablen übergebe

    int iEax,iEdx,iBit,iResult; 
    
    iEax = Edit1->Text.ToInt();
    iEdx = Edit2->Text.ToInt();
    iCl = Edit3->Text.ToInt();
    
    _asm 
    { 
        mox cl,iCl 
        mov edx,iEdx 
        mov eax,iEax 
        shrd eax,edx,cl 
        mov iResult, eax 
    }
    

    Fehlermeldung : Operants types do not match (Was passt nicht zusammen ???)



  • Keiner 'ne Ahnung ???????????????



  • Doch ich! 😃

    Also:

    Bei Der Fehlermeldung drücken wir mal F1:

    [C++ Fehler] Unit1.cpp(28): E2510 Operandengröße stimmt nicht überein

    Und da steht als Beschreibung:

    Die vom Operanden benötigte Größe stimmt nicht mit der angegebenen Größe überein.

    asm mov ax,123456;

    In diesem Beispiel gibt der Compiler einen Fehler aus, weil versucht wird, einen zu großen Wert in ein 8-Bit-Register zu verlagern.

    asm mov eax,123456;

    Die Lösung für dieses Beispiel besteht darin, den Wert in ein 32-Bit-Register zu verlagern.

    So, jetzt wissen wir, dass iCl und cl von der Bit-Länge her nicht übereinstimmen.

    cl ist ein 8 Bit-Register in das man keinen 32 Bit int laden kann, also muss man sich für iCl einen passenden Datentypen suchen ...

    [cpp]void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    int iEax,iEdx,iResult;
    __int8 iCl; //Alles klar Herr Kommissar?

    iEax = Edit1->Text.ToInt();
    iEdx = Edit2->Text.ToInt();
    iCl = Edit3->Text.ToInt();

    _asm
    {
    mov cl,iCl
    mov edx,iEdx
    mov eax,iEax
    shrd eax,edx,cl
    mov iResult, eax
    }
    }[/cpp]

    ➡ Tipp: Hilfe + Index + "Datentypen" hilft manchmal ...



  • Alles klar CHEF !!!

    Mein eigentliches Problem ist aber immer noch da.
    Die portierung in C++ mit dem Fehler bei negativen zahlen

    Dank dir trotzdem für die Nachhilfe in Assembler, vielleicht fällt dir ja was
    in meinem C++-Code auf (ist ja auch mein Hauptanliegen gewesen !)

    MfG


Anmelden zum Antworten