I'm using Visual Studio 2012 with SDL and I'm doing a simple threading task but I always get these errors:
argument of type "int (mainGame::*)(void *ptr)" is incompatible with parameter of type "int (__cdecl *)(void *)"
The other error I'm getting:
error C3867: 'mainGame::gameEvents': function call missing argument list; use '&mainGame::gameEvents' to create a pointer to member
This is how the function is written:
int gameEvents(void *ptr){
//do things here.
return 0;
}
This is the code I'm using to call the function:
SDL_Thread* gh;
gh = SDL_CreateThread(gameEvents,NULL);
Since you're using C++, you need to declare your function with C linkage, since that's what SDL expects, being a C library itself:
extern "C" int gameEvents(void *ptr);
Change gameEvents() to static. Otherwise your member function will have a "hidden" first argument for the this pointer that C APIs like SDL don't know about.
If you need access to instance data do something like this:
static int mainGame::gameEvents(void *ptr)
{
mainGame* game = (mainGame*)ptr;
//do things here.
return 0;
}
...
mainGame game;
SDL_Thread* gh;
gh = SDL_CreateThread( mainGame::gameEvents, &game );
Related
I am trying to move my FLTK projects and compile it under the VS 2015 community edition. While do this, I am getting error. I have a code like below:
#include <Fl/....>
....
class CWindow
{
private:
....
Fl_Input *_textInputEditor;
....
void _cbTextInput(Fl_Widget *refObject, void *objData)
{
// Do something when callback is triggered.
}
public:
....
void createWindow()
{
....
_textInputEditor = new Fl_Input(....);
_textInputEditor->when(FL_WHEN_ENTER_KEY);
_textInputEditor->callback((Fl_Callback*)&CWindow::_cbTextInput, this);
....
When I try to compile, I get an error:
Error C2440 'type cast': cannot convert from 'void (__thiscall CWindow::* )(Fl_Widget *,void *)' to 'Fl_Callback (__cdecl *)
This same code compiles with MinGW 5.x perfectly (IDE: C::B) under Win 7.
Can someone help me here? I want a call back to a private method of my CWindow class.
The signature is incorrect. _cbTextInput should be static. The problem then will be access to member variables.
static void _cbTextInput(Fl_Widget *refObject, void *objData)
{
// No access to member variables so cast it to a CWindow* to get
// at the member variables
CWindow* self = (CWindow*) objData;
self->cbTextInput();
// Alternatively, if you do not wish to write another routine,
// you will need to put self-> in front of every member variable
// you wish to access. Just personal preference: some people prefer
// it that way.
}
void cbTextInput()
{
// This has access to member variables
...
}
I am trying to link to an external library in my QT application. The external library has a header file with the following relevant code I'm trying to call:
extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);
In the demo C++ program provided, which has no problems compiling, the following relevant code is:
// in main.cpp
void _stdcall MyFrameSizeCallback(T x) {
do_stuff;
}
int main(int argc, char* argv[]) {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}
I am trying to incorporate this code into my QT application, but getting problems. In my mainwindow.cpp file:
void _stdcall MainWindow::MyFrameSizeCallback(T x) {
do_stuff;
}
void MainWindow::someFunction() {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}
The error I'm getting is:
error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible
What do I need to do? Thanks.
You have two problems. First, void* is a data pointer, not a function pointer. According to the C++ standard, casting between the two is not expected to work. Some platforms provide a stronger guarantee... for example Windows GetProcAddress and *nix dlsym mix the two.
Next, your &MainWindow::MyFrameSizeCallback is not a function pointer, it is a pointer-to-member-function. Calling it requires a MainWindow object, which the external library doesn't know anything about.
You need to provide an ordinary function, not a member function, to the library. If you have some way to get ahold of the MainWindow* object pointer, you can then call its member function to do the real work. Sometimes the library provides a "context" parameter which is passed to your callback; that's a great place to put the object pointer. Otherwise, you'll need to store your MainWindow* in a global variable. Easy if you have just one, while if you have more than one you might go with std::map<IGrabChannel*, MainWindow*>.
Code:
MainWindow* MainWindow::the_window;
void MainWindow::MyFrameSizeCallback(T x)
{
do_stuff;
}
void _stdcall MyFrameSizeCallbackShim(T x)
{
MainWindow::the_window->MyFrameSizeCallback(x);
}
void MainWindow::someFunction()
{
IGrabChannel* pChannel0 = something;
the_window = this;
V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}
If the parameter x isn't an IGrabChannel, change the map datatype and insertion logic accordingly. If the parameter x isn't some sort of unique predictable identifier, you may be limited to only doing callbacks to one MainWindow instance.
In some SDK I have a method which takes function pointer.
int AutoRead(nAutoRead aEventFun)
where parameter is:
typedef int (__stdcall *nAutoRead)(char *data);
Now I want to use this function in my code like this:
// First need to get pointer to actual function from DLL
CV_AutoRead AutoRead; // CV_AutoRead is typedef for using function pointer
AutoRead = (CV_AutoRead)GetProcAddress(g_hdll,"AutoRead");
// Now I want to use the SDK method and set callback function,
// but I get error on the next line
// error is: 'initializing' : cannot convert from 'int (__cdecl *)(char *)' to 'TOnAutoRead'
nAutoRead f = &callbackFunc;
if(0 == AutoRead(f)) // AutoRead - now refers to the SDK function shown initially
{
}
where callbackFunc is:
int callbackFunc(char *data)
{
}
Apparently I am doing something wrong. But what?
ps. This is typedef for CV_AutoRead
typedef int (CALLBACK* CV_AutoRead)(nAutoRead aEventFun);
This has to do with the calling convention specifier __stdcall that the callback requires. By default your callbackFunc uses __cdecl, causing an error.
To fix this problem, declare callbackFunc as follows:
int __stdcall callbackFunc(char *);
You also need to add __stdcall to the function definition.
See Argument Passing and Naming Conventions for more information on this subject.
I'm developing a simple instant-messaging software on Ubuntu 12.10, it's client requires GUI.
In the main window of the client, i need to create a thread to keep listening messages received from the server.
Here is the error message:
main.cpp:-1: In function 'int main(int, char**)':
main.cpp:27: error: invalid conversion from 'void*' to 'void* (*)(void*)' [-fpermissive]
/usr/include/pthread.h:225: error: initializing argument 3 of 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)' [-fpermissive]
In the maininterface.h:
Class MainInterface: public QWidget
{
public:
explicit MainInterface(QWidget *parent = 0);
~MainInterface();
void* ServerMSGWatch(void *threadArgs=NULL); // function run in the new thread
};
It's definition in maininterface.cpp is:
void* MainInterface::ServerMSGWatch(void *threadArgs)
{
pthread_detach(pthread_self());
char arrServerMSGRecv[SERVER_MSG_MAX_SIZE + 1];
while(1){
recv(Login::sockClnt, arrServerMSGRecv, SERVER_MSG_MAX_SIZE+1, 0);
Handle_Server_MSG(arrServerMSGRecv);
memset(arrServerMSGRecv, 0, SERVER_MSG_MAX_SIZE+1);
}
return NULL;
}
in main.cpp:
MainInterface mWindow;
mWindow.show();
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, mWindow.ServerMSGWatch(), NULL);
and in this question, i figured out that maybe there's something wrong with using a C++ compiler to compile c code.
so i tried to add a 'c_pthread.h':
#ifndef C_PTHREAD_H
#define C_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
void* ServerMSGWatch(void *threadArgs=NULL);
void Handle_Server_MSG(char *arrServerMSGRecv);
#ifdef __cplusplus
}
#endif
#endif // C_PTHREAD_H
and c_pthread.cpp:
void* ServerMSGWatch(void *threadArgs=NULL)
{
//definition
}
void Handle_Server_MSG(char *arrServerMSGRecv)
{
//definition
}
then invoke it in main.cpp:
#include "c_pthread.h"
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, ServerMSGWatch(), NULL);
but i still got the same error.
PS: sorry about some malapropisms.
You have two problems: The first is that you call the function instead of passing it. The other is more subtle, and is that you can't use a non-static class member function as a thread function.
The reason for the last problem is because non-static member function have a hidden first argument that is the this pointer.
In this case you can solve it by adding a static member function, and pass a pointer to the object as argument to the thread function. Then the static function calls the actual function in the object:
class MainInterface: public QWidget
{
public:
...
static void* StaticServerMSGWatch(void* arg)
{
reinterpret_cast<MainInterface*>(arg)->ServerMSGWatch();
return nullptr;
}
void ServerMSGWatch(); // function run in the new thread
};
...
pthread_create(&pthreadID, NULL, &MainInterface::StaticServerMSGWatch, &mWindow);
If you have a C++11 capable compiler and library, you could use std::thread instead:
std::thread myThread(&MainInterface::ServerMSGWatch, &mWindow);
As you see, you no longer need the static member function.
You're using Qt, so I strongly suggest using QThread. This will guarantee compatibility and the interop with the rest of your program will be better.
That being said, you need to pass a function pointer to pthread_create, and a member function pointer is not a function pointer: either make it static or make it a freestanding function.
In C++11, there's no need to muck around with low-level system libraries:
std::thread thread([&]{mWindow.ServerMSGWatch();});
If you're stuck with a historic version of C++ then, since you say you're using Qt, you might consider its thread class QThread.
If you're stuck with pthreads then, being a C API, it knows nothing about member functions, so you'll need a non-member, or static member function. (Strictly speaking, you should only use a non-member function declared extern "C", but in practice C++ functions will work on any sensible implementation).
So you'll need a wrapper function to call the member function:
void * CallServerMSGWatch(void * p) {
return static_cast<MainInterface*>(p)->ServerMSGWatch();
}
and tell pthread_create to pass a suitable pointer through to this:
pthread_create(&pthreadID, NULL, CallServerMSGWatch, &mWindow);
mWindow.ServerMSGWatch() is a function call.
mWindow.ServerMSGWatch is a function pointer.
I stumbled upon a rather exotic c++ namespace problem:
condensed example:
extern "C" {
void solve(lprec * lp);
}
class A {
public:
lprec * lp;
void solve(int foo);
}
void A::solve(int foo)
{
solve(lp);
}
I want to call the c function solve in my C++ member function A::solve. The compiler is not happy with my intent:
error C2664: 'lp_solve_ilp::solve' : cannot convert parameter 1 from 'lprec *' to 'int'
Is there something I can prefix the solve function with? C::solve does not work
To call a function in the global namespace, use:
::solve(lp);
This is needed whether the function is extern "C" or not.
The C functions are in the global namespace. So try
::solve(lp)
Please try ::solve
Simply ::solve(lp). Note you also need a semicolon after your class declaration.