Variable wird nach Übergabe via Pointer nicht geändert woran kanns liegen?



  • Hi leute, ich habe mal wieder ein Problem bei dem ich eure Hilfe brauche.

    Ich benutze bei einem Projekt(c++) eine Bibiliothek welche in c geschreiben ist, was an sich auch erst mal keine Probleme gemacht hatt.

    Ich habe die von der c Bibiliothek bereitgestellten Funktionen in einer Klasse gekapselt. bei einer Funktion habe ich jedoch ein Problem.

    So solte es nach der Bibiliotheksdokumentation aussehen:

    modbus_t *ctx;
    //modbus_new_tcp leifert eine adresse auf die strukt modbus_t zurück oder NULL //falls ein fehler aufgetreten ist
    ctx = modbus_new_tcp("127.0.0.1", 1502);
    if (ctx == NULL) {
        fprintf(stderr, "Unable to allocate libmodbus context\n");
        return -1;
    }
    }
    

    Das ganze habe ich in eine Fkt gepackt welche dann so aus siet:

    bool libmodbusConnector::createContext(modbus_t* mbctx, std::string ip, int port){
      mbctx = modbus_new_tcp(ip.c_str(), port);
      if (mbctx==NULL){
      return false; //kontext konte nicht eingerichtet werden
      }
    }
    

    wenn ich nun aus der main diese Funktion Aufrufe und und versuche den kontext zu erstellen, dann wird der zeiger nicht verändert, d.h. mbctx bleibt auf den initialisierten wert "hängen" und beim nächsten benutzten stürtzt das ganze ab.

    Wenn ich aber die Funktion direkt in der main aufrufe, also etwa so :

    int main(argc....){
    .
    .
      modbus_t *mbctx= modbus_new_tcp(ip, port)
      return 0;
    }
    

    dann kalppt es.
    kann mir hier jemand ein bischen Licht ins Dunkel bringen??

    Danke schonmal vorab.
    Mfg BabCom



  • Stichwort: Call by Value, Call by Reference.



  • Hallo,
    sehr einseitige Fragen heute 🤡
    Klick mich...
    MFG John.



  • ok, aber das ist glaube ich nicht wirklich das Problem??
    ich poste einfach noch mal alle relevanten stellen.

    Die Struktur moddbus_t wir im headerfile modbus.h definiert und ich habe diese auch eingebunden.

    devRead.cpp

    modbus_t *myMbCtx = NULL;
    			try{
    				//versuche einen Kontext Anzulegen
    				//so gets 
    				/*	myMbCtx = modbus_new_tcp(cfgDevice[i].getAdresse().c_str(), MBPORT);
    				if(myMbCtx == NULL){//
    					return false;
    				}*/
    
    				//so nicht
    				modbusConnector->createKontext(myMbCtx, cfgDevice[i].getAdresse(), MBPORT);
    			}catch(devReadExcept& dre){
    				throw(dre);
    			};
    			//versuche eine verbindung aufzubauen
    			try{
    				modbusConnector->connect(myMbCtx);	// Verbindung Aufbauen
    				//modbus_connect(myMbCtx);
    			}catch(devReadExcept& dre){
    				throw(dre);//fehler eine ebene tiefer werfen
    			}
    

    Die funktion:

    bool libModbusConnector::createKontext(modbus_t* mbctx, std::string ip, int port){
    
    	//Adresse wird nicht übernommen
            //der prototyfp der funktion modbus_new_tcp wird im header modbus.h definiert
            //modbus_t* modbus_new_tcp(const char *ip_address, int port);
    	mbctx = modbus_new_tcp(ip.c_str(), port);
    	if(mbctx == NULL){
    		throw devReadExcept(modbus_strerror(errno), errno, -1);
    		return false;
    	}
    	return true;
    }
    
    bool libModbusConnector::connect(modbus_t* mbctx){
    
    	if(modbus_connect(mbctx) == -1){
    		modbus_free(mbctx);
    		throw devReadExcept(modbus_strerror(errno), errno, -1);
    		//CONNECT IST FEHLGESCHLAGEN
    		return false;
    	}
    	return true;
    }
    

    Wenn ich es also wie oben auskommentiert mache dann klappts ohne Probleme.
    Wenn ich aber wie nicht auskommentiert mache dann schlägt es fehl.

    sobald die Funktion aufgerufen wird gibt die Funktion modbus_new_tcp(...) nicht mehr die Adresse der angelegten Struktur zurück sondern ändert an der Adresse garnichts.

    mfg jpk



  • BabCom schrieb:

    ok, aber das ist glaube ich nicht wirklich das Problem??

    Doch, das ist genau das Problem. Änderungen an lokalen Variablen werden generell nicht zum Aufrufer übernommen, da die übergebenen Argumente lediglich in die Parameter kopiert werden ("Call-by-value"). Um dem abzuhelfen, kann man Referenzen benutzen (oder Zeiger):

    void funktion(modbus_t*& mbctx) {
    //                     ^
      mbctx = irgendwas;
    }
    


  • ok, danke schon mal dafür das klappt soweit.

    Aber ich verstehe eigentlich nicht warum. Kann mir das jemand noch genauer erklären?

    mfg BabCom



  • void foo(int bar) 
    {
      bar = 5;
    }
    
    int main(void)
    {
     int a = 2;
     foo(a);
     //Welchen Wert hat a jetzt und warum?
      ...
    }
    




  • Hi,

    mir fällt auf, dass Du eine komische Vorstellung von exceptions hast. Du fängst eine exception um sie gleich wieder zu werfen. Erstens kannst Du im catch-block einfach ein "throw;" ohne irgendwas machen, um die selbe Exception weiter zu werfen und zweitest brauchst Du sie nicht zu fangen, wenn Du sie sowieso nur weiter wirfst. Also der Code lässt sich wesentlich vereinfachen. Statt:

    modbus_t *myMbCtx = NULL;
    			try{
    				modbusConnector->createKontext(myMbCtx, cfgDevice[i].getAdresse(), MBPORT);
    			}catch(devReadExcept& dre){
    				throw(dre);
    			};
    			try{
    				modbusConnector->connect(myMbCtx);	// Verbindung Aufbauen
    			}catch(devReadExcept& dre){
    				throw(dre);//fehler eine ebene tiefer werfen
    			}
    

    reicht:

    modbus_t *myMbCtx = NULL;
    	modbusConnector->createKontext(myMbCtx, cfgDevice[i].getAdresse(), MBPORT);
    	modbusConnector->connect(myMbCtx);	// Verbindung Aufbauen
    

    Ist doch gleich viel übersichtlicher.

    Und im createKontext macht das "return false" so gar keinen Sinn. Es wird nicht erreicht, da vorher eine Exception geworfen wird. Überhaupt brauchst Du den Rückgabewert nicht. Es wird ja sowieso immer true zurück gegeben. Mach dann gleich ein void draus.

    Dein eigentliches Problem wurde hier ja schon erläutert.



  • @DirkB
    2, da a als call by Value übergeben wird. soweit ist mir das klar.
    Im aktuellen fall habe ich nicht verstanden warum mann das so machen muss:

    void funktion(modbus_t*& mbctx
    //                     ^
    

    @tntnet
    nun ja ich fange die da, weil ich pro Ebene ggf noch weitere Informationen zu dem Fehler in meine error klasse schreibe (das ist z.B. die Sensor ID bei der der Fehler aufgetreten ist etc.), die auf höheren ebenen evtl nicht bekannt sind.
    Zugegebener maßen ist das in dem ggegebenen bsp. nicht drin weils nicht zum Problem gehört. Das ganze würde vollständig dann ca so aus sehen:

    modbus_t *myMbCtx = NULL;
                try{
                    modbusConnector->createKontext(myMbCtx, cfgDevice[i].getAdresse(), MBPORT);
                }catch(devReadExcept& dre){
                    throw(dre);
                };
                try{
                    modbusConnector->connect(myMbCtx);  // Verbindung Aufbauen
                }catch(devReadExcept& dre){
                    //weitere infos einfügen
                    int id;
                    id = cfgDevice[i].getID(); //ermittelt die aktuelle id des gelesenen sensors
                     dre.setID(id); 
                    throw(dre);//fehler eine ebene tiefer werfen
                }
    

    Desweiteren werte ich die Fehler hier aus und löse z.B. bei einem verbindungsabbruch einen Reconnect aus.

    mfg BabCom

    edit:

    tntnet schrieb:

    Und im createKontext macht das "return false" so gar keinen Sinn. Es wird nicht erreicht, da vorher eine Exception geworfen wird. Überhaupt brauchst Du den Rückgabewert nicht. Es wird ja sowieso immer true zurück gegeben. Mach dann gleich ein void draus.

    Da hast du recht. Das ist auf einer früheren Version gewachsen wo ich das noch ohne exeptions gelöst hatte.



  • BabCom schrieb:

    @DirkB
    2, da a als call by Value übergeben wird. soweit ist mir das klar.
    Im aktuellen fall habe ich nicht verstanden warum mann das so machen muss:

    void funktion(modbus_t*& mbctx
    //                     ^
    

    Weil es in deinem Fall genau das gleiche ist, nur dass der Typ nicht int, sondern modbus_t* heißt.



  • habs jetzt gerafft sry das ich so lange auf dem Schlauch stand.

    mfg BabCom


Log in to reply