return struct = lvalue?



  • Hi!

    Kurze Frage:

    Bei einem built-in type wird gemeckert (must be lvalue), doch bei struct nicht, ist das OK so?

    sockaddr_in GetAddr()
    {
    	return sockaddr_in();
    }
    
    sockaddr addr = *(sockaddr*)&GetAddr();
    

  • Mod

    Zeig mal Code, der auch nur irgendwie Sinn macht, dann kann man deine Frage beantworten. Das heißt keinen Code, der so ähnlich aussieht wie dein Code, sondern Copy & Paste mit genauer Fehlermeldung und Frage. Siehe ersten Link in meiner Signatur.



  • Hi schrieb:

    Bei einem built-in type wird gemeckert (must be lvalue), doch bei struct nicht, ist das OK so?

    Es ist ok, dass nicht gemeckert wird, das ist undefined behaviour. Da kann alles passieren, von einer Compilerwarnung bis hin zu Programmabsturz oder eine gelöschte Festplatte.

    Je nach Kontext ist dein Code allerdings sogar richtig.

    Bei diesem Code gibt es weder UB noch Speicherlecks:

    struct socke {
      socke()            { }
      socke(socke const&){ }
      socke(socke& o)    { delete o.getaddr(); }
      socke operator&()  { return socke(); }
      socke* getaddr()   { return this; }
      operator socke*()  { return new socke(); }
    };
    
    socke gib_sie_mir() { return socke(); }
    
    int main()
    {
    //===================================
      socke ok = *(socke*)&gib_sie_mir();
    //===================================
    }
    


  • Warum kann GetAddr() nicht gleich den richtigen Typ returnen?



  • dot schrieb:

    Warum kann GetAddr() nicht gleich den richtigen Typ returnen?

    +1
    Ansonsten sollte man eigentlich einfach auf sockaddr& casten können.



  • @SeppJ
    Äh es geht doch ums Prinzip, also darum, dass die structs sockaddr und sockaddr_in speichergleich sind, man aber trotzdem einen cast braucht, und ich will halt wissen, ob es direkt mit dem temporären Objekt des returns gemacht werden kann (siehe oben) oder ob man eine extra Variable anlegen muss. Fehlermeldung gibts keine.

    @ziege Warum ist das UB? Bist du dir sicher?

    @dot Weil ich sockaddr_in öfters brauche als sockaddr. Wollte deshalb nicht gleich ein template erstellen, oder wie sonst?

    @cooky451 Oh wusste gar nicht, dass das geht.

    sockaddr_in AddressToSockaddr(const Address& address)
    {
    	sockaddr_in saddr = { };
    	saddr.sin_family = AF_INET;
    	int saddrSize = sizeof(sockaddr_in);
    
    	if(WSAStringToAddress(const_cast<wchar_t*>(address.ip.c_str()), AF_INET, 0, reinterpret_cast<sockaddr*>(&saddr), &saddrSize))
    		throw Exception();
    
    	saddr.sin_port = htons(address.port);
    
    	return saddr;
    }
    
    sockaddr saddrLocal;
    
    try
    {
        // 1
    	saddrLocal = *reinterpret_cast<sockaddr*>(&AddressToSockaddr(localAddress));
    
    	// 2
    	saddrLocal = reinterpret_cast<sockaddr&>(AddressToSockaddr(localAddress));
    
    	// 3
    	sockaddr_in tmp = AddressToSockaddr(localAddress);
    	saddrLocal = *reinterpret_cast<sockaddr*>(&tmp);
    }
    

    1, 2 oder 3? Und was ist UB?



  • &AddressToSockaddr(localAddress)  // Zeile 20
    

    Das ist nicht mal erlaubt, sprich standardkonform (AFAIR funktioniert das nur in MSVC). Man kann nicht die Adresse eines prvalues nehmen.

    reinterpret_cast<sockaddr&>(AddressToSockaddr(localAddress)) // Zeile 23
    

    Das ist ebenfalls falsch. Mann kann kein prvalue zu einem Zeiger casten.

    sockaddr_in tmp = AddressToSockaddr(localAddress);
        saddrLocal = *reinterpret_cast<sockaddr*>(&tmp);
    

    Das sieht auf den ersten Blick richtig aus.



  • Naja "richtig", es gibt hier sowieso keinen mir bekannten Weg, der nicht auf UB hinausläuft...



  • Richtig ist das auch nicht, aber memcpy sollte z.B. kein UB sein. Aber auch nur, weil garantiert wird (nicht vom C++ Standard), dass die beiden structs kompatibel sind.



  • Ich nutze sowieso nur MSVC, wenn es dort kein UB ist, reicht mir das schon. Das WinAPI LEBT ja quasi von casts, es geht einfach nicht ohne.



  • Hi schrieb:

    Ich nutze sowieso nur MSVC, wenn es dort kein UB ist, reicht mir das schon. Das WinAPI LEBT ja quasi von casts, es geht einfach nicht ohne.

    Nicht wirklich. Höchstens kleine Teile der API, die Sachen machen, die aus C++ Sicht Unsinn sind und eben funktionieren, weil das OS mehr weiß als der Prozess selber.



  • Wenn dir MSVC reicht, mach was du willst. Da funktioniert in der Regel alles, was kompiliert. 🤡



  • cooky451 schrieb:

    Wenn dir MSVC reicht, mach was du willst. Da funktioniert in der Regel alles, was kompiliert. 🤡

    Jetzt ist nur die Frage ob das positiv zu bewerten ist. 😉



  • Hmm, wisst ihr denn, ob 1/2 bei MSVC garantiert nicht UB ist?



  • Hi schrieb:

    Hmm, wisst ihr denn, ob 1/2 bei MSVC garantiert nicht UB ist?

    Was UB ist bestimmt der Sprachstandard. Und wenn der etwas als UB deklariert, du es aber so und so machst weil dein spezieller Compiler das umsetzt wie gewollt, dann nutzt du das spezielle Verhalten deines Compilers aus und es besteht die Möglichkeit, dass ein anderer Compiler das ganz anders macht, und anstatt dem erwarteten Verhalten dir 10 Familienpizzen online bestellt. 😉



  • Tja, zweiter Blick... 😃



  • @Ethon
    Ich fragte nach UB bei MSVC. Dachte es wäre klar, wie ich das meine.

    Hab das gefunden http://msdn.microsoft.com/en-us/library/7zyb9yb4
    Das warning bekomme ich bei 1 und 2 (mit /W4). Geht also scheinbar mit MSVC.


Log in to reply