Seite 1 von 1

C++-Prozedur als C-Callback-Funktion

Verfasst: Fr Mai 14, 2021 7:36 am
von Leverator
Hallo zusammen,
ich habe hier ein kniffeliges Problemchen, an dem ich gestern den ganzen Tag herumgebastelt habe und eine Lösung gefunden habe, die aber eher unschön ist.

Ziel: Ich möchte ein vollständig objektorientiertes 3D-Progrämmchen basteln, das mir stereoskopische Bilder auf den 3D-Fernseher anzeigt.
Hierzu habe ich eine Klasse "window" definiert, die sich um das ganze Anzeige-Gedöns kümmern soll (MVC-Pattern halt).

Um mit der OpenGL-Hardware sprechen zu können, muss ich jedoch z.B. einen ErrorCallback als Funktionspointer an die genutzte Bibliothek übergeben.

Grobe Struktur ist also zur Zeit recht einfach:

Code: Alles auswählen

class window { ... Definitionsbums ... };
void window::ErrorCallback( int errorNo, const char* description ) { ... }
Das Problem besteht im Konstruktor der Klasse, wo der Funktionspointer in die Grafikbibliothek eingespeist werden muss.
Meine Lösung:

Code: Alles auswählen

window::window() {
    void (*fcnPtr)(int, const char*);
    fcnPtr = reinterpret_cast<void(*)(int, const char*)>(&window::ErrorCallback); // C-Funktionspointer auf C++-Prozedur (Yay!!) - aber mit Warning (Nay!!).  :)
    glfwSetErrorCallback( fcnPtr );
    
	std::cout << "Constructor window class" << std::endl;
    
}
Beim Kompilieren bekomme ich jedoch ein Warning ausgeworfen:

Code: Alles auswählen

g++ -c -std=c++17 -O2   -o window.o /home/torben/Development/eclipse-workspace/OpenGL-3D/window.cpp                                                                                                                                                                                       
/home/torben/Development/eclipse-workspace/OpenGL-3D/window.cpp: In Konstruktor »window::window()«:
/home/torben/Development/eclipse-workspace/OpenGL-3D/window.cpp:35:80: Warnung: Umwandlung von »void (window::*)(int, const char*)« nach »void (*)(int, const char*)« [-Wpmf-conversions]
   35 |     fcnPtr = reinterpret_cast<void(*)(int, const char*)>(&window::ErrorCallback); // C-Funktionspointer auf C++-Prozedur (Yay!!) - aber mit Warning. :)
      |                                                                                ^
g++ -lglfw -lGLEW -o OpenGL-3D OpenGL-3D.o window.o
Wer von Euch kann mir sagen, wie ich es so programmiere, dass die Pointerübergabe ohne Compiler-Warning funktioniert?

Viele Grüße,
Lev

Re: C++-Prozedur als C-Callback-Funktion

Verfasst: Fr Mai 14, 2021 7:53 am
von Xin
Moin Lev,

Das Definitionsbums wäre für ErrorCallback schon interessant. Du möchtest zwar super Objektorientiert laufen, nun ist der Grafikkartentreiber gar nicht so objektorientiert, wie Du Dir das wünschst: Es gibt im Callback nämlich kein "this". Die Funktion ErrorCallback muss static sein, es ist kann keine Methode sein.
Und wenn ich das hier lese:

Code: Alles auswählen

 fcnPtr = reinterpret_cast<void(*)(int, const char*)>(&window::ErrorCallback); 
ist sie das wohl nicht, wenn da eine Warninung kommt.
Dann ist die Warning berechtigt, denn das wird vermutlich knallen.

Die Methode hätte nämlich die Signatur void(*)(window *, int, char const *).

Wenn Du das objektorientiert halten willst, wird's komplizierter... nun hast Du aber vermutlich eh nur einen OpenGL-Kontext, weswegen die Kapselung in Objekte hier gar nicht so wichtig ist. Du kannst also ein Singleton als View-Implementierung für OpenGL anbieten. Hier kann in der Klasse quasi alles statisch sein, weil es ja auch alles nur einmal gibt. Entsprechend könnte eine ErrorCallback-Funktion auch auf alles zugreifen.
Was Du aber vermutlich auch nicht brauchst. Du musst da ja vermutlich einfach nur den empfangenden Text irgendwo ausgeben. Also mach ein static davor und sieh zu, dass Du das reinterpret_cast loswirst.

Ich hab jetzt spontan Lust auf Pizza, woran liegt das?

Re: C++-Prozedur als C-Callback-Funktion

Verfasst: Fr Mai 14, 2021 1:39 pm
von Leverator
Hi Xin,
danke für Deine rasche Antwort.

Ich habe es nun geändert:

Code: Alles auswählen

class window {
private:
	GLFWwindow* win;
    int error;
    char my_foo[32];    // testdaten bounce-Funktion

public:
	window();
	~window();
	int info();
    static void ErrorCallback(int, const char*);
    int initGLFW();
    int loop();
};
und

Code: Alles auswählen

static void window::ErrorCallback(int error, const char* description) {
    std::cout << "Error Callback: " << std::hex << "0x" << error << "." << description << std::endl;
}
Und erhalte:

Code: Alles auswählen

g++ -c -std=c++17 -O2   -o window.o /home/torben/Development/eclipse-workspace/OpenGL-3D/window.cpp
/home/torben/Development/eclipse-workspace/OpenGL-3D/window.cpp:53:69: Fehler: Elementfunktion »static void window::ErrorCallback(int, const char*)« kann nicht deklariert werden, statische Bindung zu haben [-fpermissive]
   53 | static void window::ErrorCallback(int error, const char* description) {
      |                                                                     ^
Ich habe mich also von einem harmlosen Warning zum fetten Error hochgeschlafen... ;)

So richtig blicke ich es nicht...


Viele Grüße,
Lev

Re: C++-Prozedur als C-Callback-Funktion

Verfasst: Fr Mai 14, 2021 2:35 pm
von Xin
Lass in der .cpp-Datei das Static vor der Definition weg. Das static in der .cpp hätte eine andere Bedeutung, wenn es C wäre.

Re: C++-Prozedur als C-Callback-Funktion

Verfasst: Fr Mai 14, 2021 3:05 pm
von Leverator
Jawoll!!

Das war es. Danke!
It's compiling like a charme...

Ohne Warnings.