[gelöst] Standardkonvertierung von vier char in ein int, aber es funktioniert nicht.


  • Mod

    kleiner Troll schrieb:

    Vermute das sich der bitshift mit der begrenzten größe von char beißt, aber kannst auch warten bis jemand antwortet der davon Ahnung hat.

    Nein, Integer promotion.

    _matze schrieb:

    Nicht +, sondern |.

    Auch nein. Was soll da der Unterschied sein?

    Der Fehler liegt woanders:

    unsigned char IP1 = 127;
      unsigned char IP2 = 9;
      unsigned char IP3 = 100;
      unsigned char IP4 = 255;
    
      unsigned int IP = (IP1 << 24) + (IP2 << 16) + (IP3 << 8) + IP4 ; // Oder mit | statt +, ist egal
    
      std::cout<<IP<<std::endl; // 2131322111. Passt.
    

    Der Fehler wird in den nachfolgenden Teilen sein. Die Umrechnung macht das was sie soll.

    Womit sich die Frage aufdrängt, wie du das getestet hast, dass du zu dieser Aussage kommst:

    Setze ich für IP direkt hexadezimal einen Wert, wird dieser korrekt eingetragen. Aber mit der unten stehenden Methode, wird immer nur der erste Byte eingetragen. Auch wenn ich es umschreibe, passiert nur etwas bei (Variable << 24). Andere Bitshifts oder gar keiner wird ignoriert. Hat dieses Byte einen Wert zwischen 0 und 127 bleibt der Rest der 32 Bit langen int 0. Hat dieses Byte einen Wert zwischen 128 und 255, wird der Rest der Bytes in der int mit 255 aufgefüllt.



  • Ich habe diese Funktion, mit der ich mir eine IP aus der Datenbank in Textform ausgeben lasse:

    std::string GLNet::getClientIP(int number)
    {
        //Abbrechen wenn Liste leer
        if(NumberClients == 0) return "Keine IP/No IP";
    
    	//IP konvertieren
    	IPaddress Adresse = ClientIP[number];
    	Uint32 IP = SDLNet_Read32 (&Adresse.host);
    	int IP1 = (IP & 0xFF000000) >> 24;//IP >> 24);
    	int IP2 = (IP & 0x00FF0000) >> 16;//(IP >> 16);
    	int IP3 = (IP & 0x0000FF00) >> 8;//(IP >> 8);
    	int IP4 = (IP & 0x000000FF);//IP;
    
    	std::stringstream KonvStream1;
        KonvStream1 << IP1;
        std::string ip1 = KonvStream1.str();
    
        std::stringstream KonvStream2;
        KonvStream2 << IP2;
        std::string ip2 = KonvStream2.str();
    
        std::stringstream KonvStream3;
        KonvStream3 << IP3;
        std::string ip3 = KonvStream3.str();
    
        std::stringstream KonvStream4;
        KonvStream4 << IP4;
        std::string ip4 = KonvStream4.str();
    
    	std::string Text;
    	Text = ip1;
    	Text += ".";
    	Text += ip2;
    	Text += ".";
    	Text += ip3;
    	Text += ".";
    	Text += ip4;
    
    	return Text;
    }
    

    Kommentiere ich das Bitshiften aus und schriebe stattdessen int IP = 0xACFFFFFF in meine Problemfunktion direkt ein, erhalte ich 172.255.255.255 als Ausgabe. Gerade nochmal getestet.
    Also nach dem Bitshiften macht die Funktion was sie tun soll. Nur in der hier geposteten Version erhalte ich ein 127.0.0.0 und wenn ich IP1 = 128 nehme, erhalte ich 128.255.255.255. Und wie bereits erwähnt, kann ich auskommentieren was ich will, nur wenn ich mit dem << 24 Bitshift zuordne, passiert etwas mit der Integer, sonst scheint gar nichts zu passieren.


  • Mod

    Ich bin jetzt etwas verwirrt, was in welcher Reihenfolge geschieht. Aber im Prinzip behauptest du doch, dass folgendes Programm nicht "123.234.110.112" ausgibt:

    #include <iostream>
    #include <string>
    #include <sstream>
    
    std::string getClientIP(int IP)
    {
        int IP1 = (IP & 0xFF000000) >> 24;//IP >> 24);
        int IP2 = (IP & 0x00FF0000) >> 16;//(IP >> 16);
        int IP3 = (IP & 0x0000FF00) >> 8;//(IP >> 8);
        int IP4 = (IP & 0x000000FF);//IP;
    
        std::stringstream KonvStream1;
        KonvStream1 << IP1;
        std::string ip1 = KonvStream1.str();
    
        std::stringstream KonvStream2;
        KonvStream2 << IP2;
        std::string ip2 = KonvStream2.str();
    
        std::stringstream KonvStream3;
        KonvStream3 << IP3;
        std::string ip3 = KonvStream3.str();
    
        std::stringstream KonvStream4;
        KonvStream4 << IP4;
        std::string ip4 = KonvStream4.str();
    
        std::string Text;
        Text = ip1;
        Text += ".";
        Text += ip2;
        Text += ".";
        Text += ip3;
        Text += ".";
        Text += ip4;
    
        return Text;
    }
    
    int main()
    {
      unsigned char IP1 = 123;
      unsigned char IP2 = 234;
      unsigned char IP3 = 110;
      unsigned char IP4 = 112;
    
      unsigned int IP = (IP1 << 24) + (IP2 << 16) + (IP3 << 8) + IP4 ;
    
      std::cout<<getClientIP(IP)<<std::endl;
    
    }
    

    Und das wird bei dir ja wohl nicht der Fall sein, oder?

    Also muss der Fehler in den von mir gekürzten Teilen liegen.


  • Mod

    Adresse.host = (Uint32)*Puffer;
    

    Ich nehme mal an das soll

    Adresse.host = *(Uint32*)Puffer;
    

    oder ähnlich heißen.
    C-Casts usw...
    Außerdem potentiell undefiniert, weil das Array ja nicht korrekt ausgerichtet sein muss.



  • SeppJ schrieb:

    kleiner Troll schrieb:

    Vermute das sich der bitshift mit der begrenzten größe von char beißt, aber kannst auch warten bis jemand antwortet der davon Ahnung hat.

    Nein, Integer promotion.

    Hm, warn Versuch wert.



  • @ Camper, sorry, aber das verstehe ich nicht. Adresse.host ist eine Uint32, also caste ich den inhalt des Arrays Puffer als Uint32. Das ist doch nur (Uint32)*Puffer oder? Bei *(Uint32)*Puffer verstehe ich gerade nicht, was es bewirken soll. 😞 Habs auchmal eingegeben, dann meckert mein Kompiler.
    Meinst du mit dem korrekt ausgerichteten Array BigEndian usw.? Das wird durch die SDLNet_Write32 bzw. -Read32 korrigiert.

    @ SeppJ, hast recht, habs einfach mal so in die main.cpp eingefügt wie du es geschrieben hast, hat funktioniert. Hab eben auch festgestellt, dass wenn ich IP = 0xACFFFFFF setze die IP zwar 172.255.255.255 ist, dass bei IP = 0xACFF00EE die IP aber weiterhin 172.255.255.255 bleibt. Also muss vom Array irgendwie falsch übertragen werden.

    So, nach ein wenig probieren habe ich eine Lösung. Das Array stückweise in ein Int kopieren:

    char Puffer[4] = {0};
    	SDLNet_Write32((Uint32)IP, Puffer);
    	IPaddress Adresse;
    	Uint32 NetIP = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8) + Puffer[3];
    	//Adresse.host = (Uint32)*Puffer;
    	Adresse.host = NetIP;
    

    Das einzig merkwürdige ist jetzt noch, dass bei diesem Code:

    bool GLNet::ServerToIP(unsigned char IP1, unsigned char IP2, unsigned char IP3, unsigned char IP4)
    {
        //Testweise andere Werte einsetzen
        IP1 = 127;
        IP2 = 9;
        IP3 = 101;
        IP4 = 255;
    	//IP konvertieren
    	/*Uint32*/unsigned int IP = (IP1 << 24) + (IP2 << 16) + (IP3 << 8) + IP4 ;
    	char Puffer[4] = {0};
    	SDLNet_Write32((Uint32)IP, Puffer);
    	IPaddress Adresse;
    	Uint32 NetIP = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8) + Puffer[3];
    	//Adresse.host = (Uint32)*Puffer;
    	Adresse.host = NetIP;
    	Adresse.port = Port;
    
    	//In Adressdatenbank eintragen
    	if(NumberClients <= 255)
    	{
    	    ClientIP[NumberClients] = Adresse;
            NumberClients++;
            return true;
    	} else {
    	    return false;
    	}
    }
    

    An der Stelle von IP3 eine 100 steht. Setze ich IP3 = 100, steht in der fertigen IP eine 99. Setze ich ihn auf 0, steht an seiner Stelle eine 255 und bei IP2 ist die Zahl um eine Stelle geringer. Kann das an irgendeinem Vorzeichenbit o.ä. liegen?

    Momentan verdreht mir SDL auch noch die Reihenfolge. In der Ausgabe erscheint die IP rückwärts, aber das ist ja eine Kleinigkeit. 😉


  • Mod

    Little Programmer schrieb:

    Momentan verdreht mir SDL auch noch die Reihenfolge. In der Ausgabe erscheint die IP rückwärts, aber das ist ja eine Kleinigkeit. 😉

    😕 Ist das nicht der Sinn des SDL-Aufrufs? Hast du überhaupt eine Ahnung, was du da machst?



  • SDLNet_Write32 dreht die IP in Netzwerkreihenfolge, SDLNet_Read32 beim Auslesen der IP aus der Datenbank dreht sie wieder zurück. Eigentlich müsste sie wieder in der richtigen Reihenfolge heraus kommen.
    Um ehrlich zu sein hab ich von Netzwerken an sich und von Netzwerkprogrammierung eigentlich keine Ahnung. Das ist gerade mein erster Versuch in die Richtung. Aber das hat ja nicht viel mit dem Umwandlungsproblem zutun.


  • Mod

    Little Programmer schrieb:

    Bei *(Uint32)*Puffer verstehe ich gerade nicht, was es bewirken soll.

    Ich auch nicht. Ist auch nicht das, was ich geschrieben habe.

    Little Programmer schrieb:

    Habs auchmal eingegeben, dann meckert mein Kompiler.

    ja, meckern sollte man ihm abgewöhnen...



  • Ah sorry, hatte mich verguckt. Ja, (Uint32)Puffer klingt logisch. Ok, ich bleibe aber lieber bei meiner byteweisen Auslesung, auch wenn da noch der Fehler drin ist, dass IP3 - 1 genommen wird. Mit (Uint32)Puffer hängt sich das Programm in einer Dauerschleife beim Aufruf der Funktion auf. Irgendwo klemmts dann, vielleicht liest es 32 Bit weise den kompletten RAM aus oder ähnliches.

    Aber ich steig noch nicht dahinter, was jetzt immer noch schief läuft. Hier die aktuelle Funktion:

    bool GLNet::ServerToIP(unsigned char IP1, unsigned char IP2, unsigned char IP3, unsigned char IP4)
    {
        if(NumberClients <= 255)
    	{
            //Testweise andere Werte einsetzen
            IP1 = 127;
            IP2 = 9;
            IP3 = 0;
            IP4 = 254;
            //IP konvertieren
            /*Uint32*/unsigned int IP = (IP1 << 24) + (IP2 << 16) + (IP3 << 8) + IP4 ;
            char Puffer[4] = {0};
            SDLNet_Write32((Uint32)IP, Puffer);
            IPaddress Adresse;
            Uint32 NetIP = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8) + Puffer[3];
            //Adresse.host = *(Uint32*)Puffer;
            Adresse.host = NetIP;
            Adresse.port = Port;
    
            //In Adressdatenbank eintragen
            ClientIP[NumberClients] = Adresse;
            NumberClients++;
            return true;
    	} else {
    	    return false;
    	}
    }
    

    Die Ausgabefunktion (hat sich nicht verändert):

    std::string GLNet::getClientIP(int number)
    {
        //Abbrechen wenn Liste leer oder kein Eintrag
        if(NumberClients == 0 || number > NumberClients) return "Keine IP/No IP";
    
    	//IP konvertieren
    	IPaddress Adresse = ClientIP[number];
    	Uint32 IP = SDLNet_Read32 (&Adresse.host);
    	int IP1 = (IP & 0xFF000000) >> 24;//IP >> 24);
    	int IP2 = (IP & 0x00FF0000) >> 16;//(IP >> 16);
    	int IP3 = (IP & 0x0000FF00) >> 8;//(IP >> 8);
    	int IP4 = (IP & 0x000000FF);//IP;
    
    	std::stringstream KonvStream1;
        KonvStream1 << IP1;
        std::string ip1 = KonvStream1.str();
    
        std::stringstream KonvStream2;
        KonvStream2 << IP2;
        std::string ip2 = KonvStream2.str();
    
        std::stringstream KonvStream3;
        KonvStream3 << IP3;
        std::string ip3 = KonvStream3.str();
    
        std::stringstream KonvStream4;
        KonvStream4 << IP4;
        std::string ip4 = KonvStream4.str();
    
    	std::string Text;
    	Text = ip1;
    	Text += ".";
    	Text += ip2;
    	Text += ".";
    	Text += ip3;
    	Text += ".";
    	Text += ip4;
    
    	return Text;
    }
    

    Und die ausgegebene IP-Adresse lautet: 254.5.9.127

    Abgesehen von der Reihenfolge habe ich eine 5 anstelle einer 6. Dieses -1 geschieht bei jedem Wert. Setze ich IP3 = 0 ein, so wird auch IP2 um eins reduziert. Die Ausgabe lautet dann 254.255.8.127.
    Meine einzige Idee wären Vorzeichenbits, aber ich habe ja unsigned Variablen genommen. Bin grad echt ratlos woher diese Wertänderungen kommen. 😞



  • Ich habe jetzt folgendes herausgefunden.

    Nach diesem Schritt:

    IP1 = 127;
            IP2 = 9;
            IP3 = 3;
            IP4 = 254;
            //IP konvertieren
            /*Uint32*/unsigned int IP = (IP1 << 24) + (IP2 << 16) + (IP3 << 8) + IP4 ;
    

    Ist IP wie es sein sollte 127.9.3.254.

    Nächster Schritt:

    char Puffer[5] = {0};
            SDLNet_Write32((Uint32)IP, Puffer);
            IPaddress Adresse;
            Adresse.host = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8) + Puffer[3];
    

    Hier ist Adresse.host nun 127.9.2.254.

    Die 2 erhalte ich nur nicht, wenn ich folgendermaßen auskommentiere:

    Adresse.host = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8);// + Puffer[3];
    //bzw.
    Adresse.host = (Puffer[0] << 24) + (Puffer[1] << 16) + (Puffer[2] << 8) + 0xFF;// + Puffer[3];
    

    Dann ist Adresse.host 127.9.3.0 bzw. 127.9.3.255. Der letzte Byte aus dem Puffer überschreibt die 3 teilweise, aber wie kann das sein, bzw. wie kann ich das verhindern? Wenn ich für den Puffer nur die Länge 4 Bytes nehme, damit er nciht noch Teile vom fünften kopieren kann o.ä., also char Puffer[4] = {0}, ändert das nichts.

    Und nun zum zweiten Problem. Während SDLNet_Write32 zumindest auf meinem Computer nichts an der Variablen ändert, kehrt SDLNet_Read32 die Variable um, weshalb ich auch die Ausgabe verkehrt herum hatte. Aber dafür muss ich wohl nochmal wo anders einen Thread starten. SDL-spezifisch gehört hier ja nicht rein.



  • Das sieht danach aus, als ob du ein Vorzeichen-Problem hast - (signed char)254 == -2. Bei solchen Operationen solltest du lieber mit unsigned char arbeiten und eventuell doch auf Bit-Operationen umstellen.



  • Ich hab doch schon unsigned char. hatte auch schon als Ziel unsigned Int probiert, aber das hat nichts geändert. Was meinst du mit Bit-Operationen? Bitshiften ist doch eine oder?



  • Little Programmer schrieb:

    Ich hab doch schon unsigned char. hatte auch schon als Ziel unsigned Int probiert, aber das hat nichts geändert.

    Das Endziel ist unsigned, der Zwischenspeicher char Puffer[5]; ist es vermutlich nicht*.

    Was meinst du mit Bit-Operationen? Bitshiften ist doch eine oder?

    Es wurde zwar schonmal erwähnt, aber Bit-Oder gehört auch dazu.

    Edit: (da ist doch glatt eine Fußnote verlorengegangen)
    * ob ein blanker "char" vorzeichenbehaftet ist oder nicht, ist compilerspezifisch



  • Ah, klar. Jetzt wo du's sagst. An unsigned char Puffer[5] hatte ich gar nicht gedacht. Jetzt funktionierts. Halt abgesehen von der SDL-Umwandlung, aber das ist ein anderes Thema. Ging hier ja nur um die vier Bytes in eine Int.

    Vielen Dank an alle die mir geholfen haben. 🙂


Anmelden zum Antworten