[gelöst] Problem mit Funktionszeiger



  • Stonecold_Mario schrieb:

    So nun aber zu meinem Problem, dass immer noch nicht gelöst ist. Weißt du Rat?

    Nein. Der gezeigte Code funktioniert. Wenn du "angepassten" oder "Beispiel"-Code zeigst, solltest du sicherstellen, dass dieser Code auch das Fehlverhalten reproduziert. Ansonsten bringt das gar nichts.

    So kann man nur vermuten, dass du im echten Code etwas falsch machst, diesen Fehler aber nicht in deine Beispiele überträgst.



  • Okay danke dir. Werde nachher nochmal den Beispielcode und auch meinen eigenen testen und mich dann wieder melden. Evtl. versuche ich mal meinen den betreffenden Teil meines Codes zu posten.

    Gruß,
    Mario



  • Hallo MFK,

    ich habe den Beispielcode von heute morgen mal probiert und dieser läuft bei mir auch. Sorry hatte gehofft, dass er den selben Fehler produziert. Mein Fehler ist aber immer noch da und ich weiß nicht so recht warum. Bin gerade dabei eine Lib für die Kommunikation mit ner Seriellen Schnittstelle zu bauen. Ich weiß, vergleichbares gibt es im Netz aber gerne auch verstehen was ich benutze und deshalb versuche ich es halt selber mal. Im Grunde funktioniert auch alles so weit nur die Sache mit dem Funktionszeiger nicht. Würde dir gerne das kleine Projekt mal zukommen lassen doch leider kann ich dem Beitrag scheinbar nicht anhängen.

    Soll ich den kompletten Code hier posten?

    Gruß,
    Mario



  • versuche den code soweit wie möglich zu kürzen, so dass der fehler aber trotzdem noch auftritt.
    ach, und poste zuallererst mal die fehlermeldung, die dir dein compiler ausgibt.



  • Okay hier mal der Code. BasisThread ist wie der Name schon sagt eine Basisklasse für einen Win32-Thread.

    ReceiverThread.h

    #ifndef RECEIVERTHREAD_H
    #define RECEIVERTHREAD_H
    
    #include <windows.h>
    
    #include "BasisThread.h"
    
    class SerialCommunicator;
    typedef void (SerialCommunicator::*funptr) (void);
    
    class ReceiverThread : public BasisThread
    {
    public:
    	ReceiverThread();
    	~ReceiverThread();
    
    	void setData(HANDLE* inHandle, OVERLAPPED* inReadOverlapped, funptr p, SerialCommunicator* obj);
    
    protected:
    	virtual int run(void);
    
    private: 
    	HANDLE*		h_comm;
    	OVERLAPPED*	m_readOverlapped;
    	//void		callBack();	
    
    	funptr ptr;
    };
    
    #endif // RECEIVERTHREAD_H
    

    ReceiverThread.cpp

    #include "ReceiverThread.h"
    
    #include <iostream>
    
    ReceiverThread::ReceiverThread() : BasisThread()
    {
    
    }
    
    ReceiverThread::~ReceiverThread()
    {
    
    }
    
    void ReceiverThread::setData(HANDLE* inHandle, OVERLAPPED* inReadOverlapped,  funptr p, SerialCommunicator* obj)
    {
    	ptr = p;
    	std::cout << "ReceiverThread::setData(): obj = " << obj << " fun = " << p << std::endl;
    	(*obj.*ptr)();
    	THREAD_SAFE_ACCESS
    	{
    		h_comm				= inHandle;
    		m_readOverlapped	= inReadOverlapped;
    	}
    	END_THREAD_ACCESS
    }
    
    int ReceiverThread::run(void)
    {
    	while(1)
    	{
               // Aufgabenerfüllung
    
    	}
    }
    

    SerialCommunication.h

    #ifndef SERIALCOMMUNICATION_H
    #define SERIALCOMMUNICATION_H
    
    #include <windows.h>
    
    static const unsigned int RECEIVEBUFFER_LENGTH	= 256; 
    static const unsigned int COMPORT_LENGTH		= 8;
    static const unsigned int PREFIX_LENGTH			= 8;
    
    // forward declaration
    class ReceiverThread;
    
    class Publisher
    {
    public:
    	virtual void dataReceived() = 0; // callback if data received on COM-Port 
    };
    
    class SerialCommunicator
    {
    
    public:
    	static enum sc_parity
    	{
    		sc_parity_evenparity = 0,
    		sc_parity_markparity,
    		sc_parity_noparity,
    		sc_parity_oddparity,
    		sc_parity_spaceparity
    	};
    
    	static enum sc_stopbits
    	{
    		sc_stopbits_onestopbit = 0,
    		sc_stopbits_one5stopbit,
    		sc_stopbits_twostopbit
    	};
    
    	SerialCommunicator(Publisher* pubObj);
    	~SerialCommunicator();
    
    	HANDLE openCommunication(const char* port);
    
    	BOOL		setDCB(	HANDLE handle, 
    						const int baudrate		= 9600, 
    						const int bytesize		= 8, 
    						sc_parity parity		= sc_parity_noparity, 
    						sc_stopbits stopbits	= sc_stopbits_onestopbit);
    
    	BOOL		setTimeOuts( unsigned int readIntervalTimeOut			= 100,
    							 unsigned int readTotalTimeoutMultiplier	= 0,
    							 unsigned int readTotalTimeoutConstant		= 1,
    							 unsigned int writeTotalTimeoutMultiplier	= 0,
    							 unsigned int writeTotalTimeoutConstant		= 0 );
    
    	int			sendData( bool& isWritten, 
    						  const char* msg = NULL, 
    						  bool withPrefix = false);
    
    	char*		receiveData( int& noOfReceivedBytes, 
    							 BOOL& isRead);
    
    	const char* getComPort(); 
    
    	BOOL		closeCommunication(HANDLE handle);
    	void		incommingData();
    
    private:
    
    	HANDLE			h_comm;
    	DCB				m_dcb;
    	COMMTIMEOUTS	m_timeOuts;
    	ReceiverThread* t_receiverThread;
    	OVERLAPPED      m_readOverlapped;
    	OVERLAPPED      m_writeOverlapped;
    	char			m_comPort[COMPORT_LENGTH];
    	char			m_progPrefix[PREFIX_LENGTH];
    	Publisher*		p_publisherObject;
    	char			m_receiveBuffer[RECEIVEBUFFER_LENGTH];
    };
    
    #endif //SERIALCOMMUNICATION_H
    

    SerialCommunication.cpp

    #include "SerialCommunication.h"
    
    #include <iostream>
    #include <sstream>
    
    #include "ReceiverThread.h"
    
    SerialCommunicator::SerialCommunicator(Publisher* pubObj) //: p_publisherObject(pubObj)
    {
    	p_publisherObject = static_cast<Publisher*>(pubObj); 
    	memset(&m_dcb, 0, sizeof(m_dcb));
    	memset(&m_timeOuts, 0, sizeof(m_timeOuts));
    	memset(m_comPort, '\0', COMPORT_LENGTH);
    	memset(&m_readOverlapped, 0 ,sizeof(m_readOverlapped));
    	memset(&m_writeOverlapped, 0 ,sizeof(m_writeOverlapped));
    
    	m_readOverlapped.hEvent		= CreateEvent( NULL, FALSE, FALSE, NULL ); 
    	m_writeOverlapped.hEvent	= CreateEvent( NULL, FALSE, FALSE, NULL ); 
    
    	h_comm				= INVALID_HANDLE_VALUE; // Initialisierung des Handle
    	t_receiverThread	= new ReceiverThread();
    
    	m_progPrefix[0] = char(0xE6);
    	m_progPrefix[1] = char(0xB5);
    	m_progPrefix[2] = char(0xBA);
    	m_progPrefix[3] = char(0xB9);
    	m_progPrefix[4] = char(0xB2);
    	m_progPrefix[5] = char(0xB3);
    	m_progPrefix[6] = char(0xA9);
    	m_progPrefix[7] = '\0';
    }
    
    SerialCommunicator::~SerialCommunicator()
    {
    	closeCommunication(h_comm);
    	delete t_receiverThread;
    }
    
    HANDLE SerialCommunicator::openCommunication(const char* port)
    {
    	closeCommunication(h_comm);
    	strncpy_s(m_comPort, COMPORT_LENGTH -1, port,  COMPORT_LENGTH -1);
    
    	h_comm = CreateFile( m_comPort, 
    						  GENERIC_READ | GENERIC_WRITE, 
    						  0, 
    						  0,
    						  OPEN_EXISTING,
    						  FILE_FLAG_OVERLAPPED, // 0, ++++++++ WAS MACHT DAS FILE_FLAG_OVERLAPPED
    						  0);
    
    	if (h_comm == INVALID_HANDLE_VALUE)
    	{
    
    		//int error = GetLastError();
    		CloseHandle(h_comm);
    		return NULL;
    	}
    	else 
    	{	
     		t_receiverThread->setData(&h_comm, &m_readOverlapped, &SerialCommunicator::incommingData, this);
    		std::cout << "SerialCommunicator::openCommunication(): obj = " << this << " fun = " << &SerialCommunicator::incommingData << std::endl;
    		t_receiverThread->startThread();
    		return h_comm;
    	}
    }
    
    int SerialCommunicator::sendData(bool& isWritten, const char* msg, bool withPrefix)
    {
    	std::ostringstream sstr;
    	if(withPrefix)
    	{
    		sstr << m_progPrefix << msg;
    		/*std::cout << sstr.str().c_str() << " --- " << m_progPrefix << " --- " << msg << std::endl;*/
    	}
    	else
    	{
    		sstr << msg;
    	}
    
    	DWORD numberOfBytesWritten;
    	if(WriteFile(h_comm, sstr.str().c_str(), sstr.str().length(), &numberOfBytesWritten, &m_writeOverlapped))
    	{
    		isWritten = true;
    	}
    	else
    	{ 
    		if(ERROR_IO_PENDING == GetLastError())
    		{
    			if( WAIT_OBJECT_0 == WaitForSingleObject( m_writeOverlapped.hEvent, 200 ) ) 
    			{
    				isWritten = true;
    			}
    			else 
    			{
    				isWritten = false;
    			} 	
    		}
    		else
    		{
    			isWritten = false;
    		}
    	}
    	return numberOfBytesWritten;
    }
    
    char* SerialCommunicator::receiveData(int& noOfReceivedBytes, BOOL& isRead)
    {
    	memset(m_receiveBuffer, '\0', RECEIVEBUFFER_LENGTH);
    	DWORD NumberOfBytesRead;
    
    	if(ReadFile(h_comm, m_receiveBuffer, RECEIVEBUFFER_LENGTH-1, &NumberOfBytesRead, &m_readOverlapped))
    	{
    		isRead = true;
    	}
    	else
    	{
    		if(ERROR_IO_PENDING == GetLastError())
    		{
    			if( WAIT_OBJECT_0 == WaitForSingleObject( m_readOverlapped.hEvent, 200 ) ) 
    			{
    				isRead = true;
    			}
    			else 
    			{
    				isRead = false;
    			} 	
    		}
    		else
    		{
    			isRead = false;
    		}
    	}
    	noOfReceivedBytes = NumberOfBytesRead;
    	return m_receiveBuffer;
    }
    
    BOOL SerialCommunicator::setDCB(HANDLE hCom, const int baudrate, const int bytesize, sc_parity parity, sc_stopbits stopbits)
    {
    	//BOOL fSuccess = GetCommState(h_comm, &m_dcb);
    	m_dcb.BaudRate = baudrate;
    	m_dcb.ByteSize = bytesize;
    
    	switch(parity)
    	{
    		case sc_parity_evenparity:	m_dcb.Parity = EVENPARITY;	break;
    		case sc_parity_markparity:	m_dcb.Parity = MARKPARITY;	break;
    		case sc_parity_noparity:	m_dcb.Parity = NOPARITY;	break;
    		case sc_parity_oddparity:	m_dcb.Parity = ODDPARITY;	break;
    		case sc_parity_spaceparity: m_dcb.Parity = SPACEPARITY;	break;
    		default:					m_dcb.Parity = NOPARITY;	break;
    	}
    
    	switch(stopbits)
    	{
    		case sc_stopbits_onestopbit:	m_dcb.StopBits = ONESTOPBIT;	break;
    		case sc_stopbits_one5stopbit:	m_dcb.StopBits = ONE5STOPBITS;	break;
    		case sc_stopbits_twostopbit:	m_dcb.StopBits = TWOSTOPBITS;	break;
    		default:						m_dcb.StopBits = ONESTOPBIT;	break;
    	}
    
    	return SetCommState(h_comm, &m_dcb);
    }
    
    BOOL SerialCommunicator::setTimeOuts( unsigned int readIntervalTimeOut,
    									  unsigned int readTotalTimeoutMultiplier,
    									  unsigned int readTotalTimeoutConstant,
    									  unsigned int writeTotalTimeoutMultiplier,
    									  unsigned int writeTotalTimeoutConstant )
    {
    	m_timeOuts.ReadIntervalTimeout			= readIntervalTimeOut;
    	m_timeOuts.ReadTotalTimeoutMultiplier	= readTotalTimeoutMultiplier;
    	m_timeOuts.ReadTotalTimeoutConstant		= readTotalTimeoutConstant;
    
    	m_timeOuts.WriteTotalTimeoutMultiplier	= writeTotalTimeoutMultiplier;
    	m_timeOuts.WriteTotalTimeoutConstant	= writeTotalTimeoutConstant;
    
    	return SetCommTimeouts(h_comm,&m_timeOuts);
    }
    
    const char* SerialCommunicator::getComPort()
    {
    	return m_comPort;
    }
    
    BOOL SerialCommunicator::closeCommunication(HANDLE handle)
    {
    	t_receiverThread->killThread();
    
    	BOOL retVal = true;
    	//if(handle != INVALID_HANDLE_VALUE)
    	//{
    		retVal	= CloseHandle(handle);
    		handle	= INVALID_HANDLE_VALUE;
    	//}
    	return retVal;
    }
    
    void SerialCommunicator::incommingData()
    {
    	std::cout << "############################\n";
    	p_publisherObject->dataReceived();
    }
    

    Ich habe versucht nur das Notwendigste zu posten. Kann sein dass irgendwo noch ne Klammer fehlt oder so. Das VS2005 Projekt kann ich per Mail verschicken.

    Das Problem findet sich in ReceiverThread::setData(...);

    Danke für die Hilfe!



  • queer_boy schrieb:

    versuche den code soweit wie möglich zu kürzen, so dass der fehler aber trotzdem noch auftritt.
    ach, und poste zuallererst mal die fehlermeldung, die dir dein compiler ausgibt.

    340 Zeilen sind nicht sehr gekürzt..



  • Der Kompiler gibt keine Fehlermeldung aus. Alles lässt sich wunderbar bauen.

    Wenn ich in in der setData-Funktion von ReceiverThread bin, ist der übergebene this-Pointer (hier *obj) gleich 0.



  • Stonecold_Mario schrieb:

    Der Kompiler gibt keine Fehlermeldung aus. Alles lässt sich wunderbar bauen.

    Wenn ich in in der setData-Funktion von ReceiverThread bin, ist der übergebene this-Pointer (hier *obj) gleich 0.

    Na dann schau mal, wieso der 0 ist. (Dann musst du aber zum Aufrufer von setData gehen.

    Also hier:
    SerialCommunicator::openCommunication



  • Sicher, nur sehe ich nicht warum this nun 0 ist.

    t_receiverThread->setData(&h_comm, &m_readOverlapped, &SerialCommunicator::incommingData, this);
    std::cout << "SerialCommunicator::openCommunication(): obj = " << this << " fun = " << &SerialCommunicator::incommingData << std::endl;
    

    Die Ausgabe zeigt ja eine Objektadresse != 0



  • Wenn du da mit dem Debuger Schrit für Schritt dann in die Funktion reingehst, und vorher die Adresse nicht 0 hast und beim nächsten Schritt ist in der Funktion 0? - Kann ich mir nur schwer vorstellen.



  • Nur mal die Sachen die aufgefallen sind.

    Funktionsaufruf:

    this 0x009f5110 {h_comm=0x00000ee4 m_dcb={...} m_timeOuts={...} ...} SerialCommunicator * const

    h_comm 0x00000ee4 void *

    t_receiverThread 0x009f4d68 {h_comm=0xcdcdcdcd m_readOverlapped=0xcdcdcdcd ptr=0xcdcdcdcd } ReceiverThread *

    p_publisherObject 0x009938dc {serialCom=0x009f5110 hCom=0xffffffff } Publisher *

    Nächster Schritt:
    obj 0x00000000 {h_comm=??? m_dcb={...} m_timeOuts={...} ...} SerialCommunicator *

    h_comm CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden

    t_receiverThread CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden

    p_publisherObject CXX0017: Fehler: Symbol "" nicht gefunden

    Ich erkenne ein Problem. Weiß aber nicht warum es da ist.



  • Sind bezüglich der Meldungen im Debugger nur keine vernünftigen Debuginfos für die Lib erstellt worden? Wo kann ich das im VC2005 für die statische Lib einstellen (/DEBUG)? Linkereinstellungen gibt es für die Lib ja nicht?



  • Okay ich habe hier nochmal das Beispiel von heute morgen so gebaut, dass ebenfalls der selbe Fehler auftritt. Ist jetzt vielleicht einfacher nachzuvollziehen. Ich werde nicht schlau.

    A.h

    #ifndef A_H
    #define A_H
    
    class B; 
    
    typedef void (B::*funptr) (void); 
    
    class A { 
     private: 
      funptr ptr; 
     public: 
    	 void callFunction(funptr p, B* obj);
    }; 
    
    #endif // A_H
    

    A.cpp

    #include "A.h"
    
    void A::callFunction(funptr p, B* obj) { ptr = p; (*obj.*ptr)(); }
    

    B.h

    #ifndef B_H
    #define B_H
    
    class B { 
     public: 
      void callHallo();
    
      void run();
    };
    
    #endif // B_H
    

    B.cpp

    #include "B.h"
    
    #include <iostream> 
    #include "A.h"
    
    void B::callHallo() { std::cout << "Hallo Welt!\n"; } 
    
    void B::run() 
    { 
    A* obj = new A; 
    obj->callFunction(&B::callHallo, this); 
    }
    

    main.cpp

    #include "B.h"
    
    int main() { 
      B* obj = new B; 
      obj->run(); 
    }
    

    Es scheint problematisch zu sein, wenn die Funktion callFunction der Klassen A in einer seperaten cpp-Datei implementiert wird. 😕

    Schönen Abend noch!!!



  • #include "A.h" //zuerst
    #include "B.h"
    
    #include <iostream>
    
    void B::callHallo() { std::cout << "Hallo Welt!\n"; }
    
    void B::run()
    {
    A* obj = new A;
    obj->callFunction(&B::callHallo, this);
    }
    


  • Wow danke,

    genau das war das Problem. Jetzt funktioniert es auch bei meinen Prog.
    Da wäre ich so schnell nicht drauf gekommen, wenn überhaupt.

    Was genau ist jetzt das Problem gewesen. Warum ist es wichtig die Reihenfolge der Includes zu beachten?

    Nochmal danke und Gruß,
    Mario


  • Mod

    Stonecold_Mario schrieb:

    Warum ist es wichtig die Reihenfolge der Includes zu beachten?

    Ist es eigentlich nicht. Du könntest ein Problem mit einer nicht standardgemäßen Optimierung deines Compilers haben (etwa Visual C++: benutz zur Sicherheit den Schalter /vmg). Das Problem würde dann auch nicht auftreten, wenn du Zeiger auf Member nie deklarierst, bevor die betreffende Klasse definiert wurde (was meistens möglich ist; hier: vor der Klassendefinition von A den Header für B einbinden).



  • Okay danke!

    Wie bist du darauf gekommen einfach die Includes zu vertauschen?

    Das Programmstück welches ich dort gerade baue ist eine statische Lib. Deshalb wollte ich in jedem Fall vermeiden einen Nicht-Standard-Header zu includieren.
    Bin echt froh, dass das Problem vom Tisch ist, hat echt aufgehalten.

    Nochmal danke auch an all die Anderen, die sich mit dem Problem beschäftigt haben.



  • Stonecold_Mario schrieb:

    Das Programmstück welches ich dort gerade baue ist eine statische Lib. Deshalb wollte ich in jedem Fall vermeiden einen Nicht-Standard-Header zu includieren.

    Das spielt doch keine Rolle. Es müssen ja so oder so beide Teile vorhanden sein, sonst kann das gar nicht funktionieren. Was unbedingt ferngehalten werden muss, sind Sachen, die mal gar nichts mit deinem Projekt zu tun haben. Respektive nicht zur lib gehören.



  • Ja, aber so reicht es jetzt für weitere Projekte aus, den Header der Lib und die .lib selber zu haben. Ansonsten hätte ich mindestens noch den Klasse B Header benötigt.


Anmelden zum Antworten