[SOLVED] Question about calling a C++ function from a C routine
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Question about calling a C++ function from a C routine
I have a complicated library for Bluetooth LE that I want to incorporate in Qt. Unfortunately, the library is in C and I would really like to not have to port it to C++.
I have managed to do the following where I can call SendData which is in my C++ file, from a C file, but I cannot then call SendBTLEDataWrapper because it tells me it's out of scope.
Is there any way I can pass the data and the pointers from SendData to SendBTLEData? If I try calling SendBTLEData directly, and forcing that to be a C routine, my call to the virtual com part class is then out of scope.
I seem close, but can't just bridge those two routines. Anyone know if it is possible?
I have managed to do the following where I can call SendData which is in my C++ file, from a C file, but I cannot then call SendBTLEDataWrapper because it tells me it's out of scope.
Is SendBTLEData inside a class or namespace? You just need to use the fully qualified name:
ntubski hit the major issue, but his specific suggestion only works for a namespace or a static function in a class.
You haven't told us what SendBTLEDataWrapper is, but I will guess from context that it is a non static function in a class.
Quote:
Originally Posted by DiBosco
my call to the virtual com part class
I don't know what "virtual com part class" means.
Whenever you call a non static function in a class, you need to use an object of that class.
That fact may be less obvious to a beginning C++ programmer, because you often call a function in a class from another function in the same class and in that case you usually don't explicitly specify the object to be used. You may not realize that every such call implicitly uses a reference to (*this).
Another GUESS about what you are doing. You probably have a "singleton" situation, meaning the whole program has only one object of that class (whatever class contains SendBTLEDataWrapper) and having only one of those is fundamental to the design (not an accident of the current simplicity).
If that is correct, you should look up some examples of how to program with C++ singletons. It is very common to want a function declared extern C to call a non static member function of a singleton class. The best way to do that is to create a static member function of that class whose job it is to return a reference or pointer to the singleton object. Then each extern C function must call the static function to get the singleton then use that to call the desired non static function.
Somewhere else you need to arrange for the singleton object to be created and for that static function to know the pointer to the singleton. There are many different ways to do that, and I can't guess what fits well in the rest of what you have done, which is why I suggested you look at some examples of singleton programming to see what fits in.
I haven't tested the following, so I might have forgotten a detail, but one approach to singleton design is:
In that example, I made the constructor for X private so no outside function can call it (also no class can derive from X) then I made the singleton object be function static inside the singleton() function.
So the first time any code calls X::singleton() the object will be created. Then all subsequent calls to X::singleton() will get a reference to that same object.
That all assumes it is OK to do the original construction of the object using a default constructor. If that is not OK, that could lead to a very different implementation of singleton(), but should still allow X::singleton() to be used the same way.
SendBTLEDataWrapper accesses a qextserialport class which gives me access to a serial port - which in this case is a virtual com port. ie One of those USB to serial port [USB] classes. The fact it's a virtual com port is not relevant really. Just take it that it's a good old fashioned com port for sending and receiving data.
The BTLE library, once it has put a message together, calls a function which - in my C code on my embedded micro - I simply let the library access by saying:
bglib_output = SendBTLEDataWrapper
bglib_output is the library function which has data passed to it in the form of two pointers to data to send out, and two data lengths associated with those pointers.
So, when the library calls bglib_output, it is really calling my SendBTLEDataWrapper, which quite simply sends a few bytes of data out of the UART.
Now, we talked about the method suggested by ntubski on the tram into town yesterday and I was asking what it meant when you used this method of:
classname::functionname()
So, my friends, who are much more experienced in C++ than me, explained it was a way of making it a static function which seems to be what johnsfine hit on. (I didn't see reply that until today).
Using that method does not work because it tells me:
Code:
error: cannot call member function 'void MainWindow::wo(unsigned char, char*, unsigned char, char*)' without object
Googling around for this shows other instances of people finding this which so far I don't understand. (I'm not very good/experienced at C++.)
I have read through the singleton explanation from johnsfine, but don't understand it, so I'll do some Googling about for Singleton syntax.
So, my friends, who are much more experienced in C++ than me, explained it was a way of making it a static function
That odd phrase makes me think you don't quite understand yet.
That syntax is a way of calling the function if it already is a static function. But it appears the function you wanted to call wasn't a static function.
Quote:
Using that method does not work because it tells me:
Now I'm back to guessing. But I think you mean you changed the declaration of the function you wanted to call, so that function was static. Then that function wouldn't compile because the things it calls aren't also static.
If you have friends who explained that much, maybe they can explain how to work with a "singleton".
Your error message including "MainWindow" is another hint that you need to use a singleton.
Googling around for this shows other instances of people finding this which so far I don't understand. (I'm not very good/experienced at C++.)
In a nutshell, as Johnsfine was attempting to explain, in C++, you can only make a call to a static declared function (whether in a class or outside of one), or to one in which you have an instance of an object. This last part regarding having a class instance is of paramount importance to understand if you plan to become proficient in C++.
Declaring a static function within a class would be something like:
Code:
class MyClass
{
public:
static void myFunction(); // implemented elsewhere
};
int main()
{
MyClass::myFunction(); // Ok
myFunction(); // Bad -- requires that you specify the class name
}
Alternatively, if the function is merely declared within a namespace:
Code:
namespace MyNameSpace
{
void myFunction(); // implemented elsewhere
}
int main()
{
MyNameSpace::myFunction(); // Ok
myFunction(); // Can be used as such if 'using namespace MyNameSpace' directive specified; otherwise will fail
}
If you declare the function within a class, and it is not declared static, then you must have an instance object of that class. For example:
Code:
class MyClass
{
public:
MyClass(); // class constructor; implemented elsewhere
void myFunction(); // implemented elsewhere
};
int main()
{
MyClass mc; // here an instance of MyClass is declared.
mc.myFunction(); // now it is ok to call myFunction().
}
Note that if you do not specify a constructor for your class, the compiler will auto-generate one for you. This may not be desirable, depending on your needs.
If you declare the function within a class, and it is not declared static, then you must have an instance object of that class. For example:
All that explanation was correct. But in the exact same situation, I have seen nearly the same explanation consistently lead beginners to another error rather than to the correct path.
If you just understand that you need an object, but still don't really understand why, the obvious solution (similar to your example) is to create the object where you need it. If you need the object at the beginning of main(), as in your example, that is probably correct.
But in the situation the OP is asking about, it is almost certainly wrong to create the object where it is needed. But that is what most beginners would be led to do by your explanation. That approach would satisfy the compiler, but would not act correctly at run time.
I'm pretty sure what is required here is to have a singleton object and to access that singleton object where needed.
All that explanation was correct. But in the exact same situation, I have seen nearly the same explanation consistently lead beginners to another error rather than to the correct path.
If you just understand that you need an object, but still don't really understand why, the obvious solution (similar to your example) is to create the object where you need it. If you need the object at the beginning of main(), as in your example, that is probably correct.
But in the situation the OP is asking about, it is almost certainly wrong to create the object where it is needed. But that is what most beginners would be led to do by your explanation. That approach would satisfy the compiler, but would not act correctly at run time.
I'm pretty sure what is required here is to have a singleton object and to access that singleton object where needed.
There are cases were it is customary to declare a temporary object within a C function (that serves as a wrapper around a C++ interface). A singleton object would not be warranted in this case, and certainly not an object that has been declared with greater scope. If the object needs to be used multiple times, then it would be wiser to declare this object at a higher level, and then use it when making the C function calls.
Anyhow, another example:
Code:
class Status
{
public:
bool isGood();
...
};
class Socket
{
public:
Socket();
Status connect(...);
...
};
// C wrapper...
typedef void* SOCKET;
SOCKET CreateSocket()
{
return new Socket;
}
int Connect(SOCKET sock, ...)
{
Status status = reinterpret_cast<Socket*>(sock)->connect(...); // here a local object is declared
return status.isGood() ? 0 : 1;
}
void DestroySocket(SOCKET sock)
{
delete reinterpret_cast<Socket*>(sock);
}
...
int main()
{
SOCKET mySock = CreateSocket(...);
if (Connect(mySock) != 0)
{
// error
return -1;
}
...
DestroySocket(mySock);
return 0;
}
Note how in Connect(), that the 'status' object, albeit a C++ class type, was declared and used locally. It is understood that its usefulness will expire once the function exits.
Last edited by dwhitney67; 03-03-2013 at 08:20 AM.
That odd phrase makes me think you don't quite understand yet.
That syntax is a way of calling the function if it already is a static function. But it appears the function you wanted to call wasn't a static function.
Oops, yes, I did not word that well. I did mean to say I declared it as a static function (this morning) - once it had been explained to me.
Quote:
Originally Posted by johnsfine
Now I'm back to guessing. But I think you mean you changed the declaration of the function you wanted to call, so that function was static. Then that function wouldn't compile because the things it calls aren't also static.
2) Before you added the extern C stuff and/or if you comment out the problem part of that to make it build, is the constructor of that class ever called?
3) Is that class and its functions entirely defined in an hpp file? Or have you followed the good practice of defining the class in an hpp, but defining any non trivial functions in a cpp file?
If you post the beginning of the class definition and its constructor definition, assuming a yes to question 2, I can give you better specifics about how to adapt it as a singleton (if the suggestion later in this post isn't enough). If there is not already exactly one call to that constructor, then you have more serious project level design issues that need to be fixed before using the singleton design.
The singleton example I gave earlier is the simplest way to set up a singleton class in a new project. But it isn't appropriate for all situations and may be difficult to adapt into an existing class. A more general and more adaptable approach is:
a) Inside the class definition declare a static member variable, which is a pointer to an object of that class.
b) The pointer declared in (a) must be defined in a cpp file and initialized there to zero.
c) The singleton() function should be defined to return that object, either as a reference or as a pointer, whichever you are more comfortable with. That singleton function is best defined in the hpp, not the cpp.
d) The constructor should be changed to error out if the pointer declared in (b) is already nonzero. Otherwise it should set that pointer equal to this. That constructor ought to be in the cpp file, not the hpp.
Each ... represents whatever is already in that part of your class definition. The error_out should be something that reports the serious error condition of constructing the singleton more than once.
The use of X::singleton() in the extern C functions is the same in this example as in my previous. The implementation of singleton() this way is entirely different, but the use of the singleton() function is the same.
Actually, with a Singleton, the constructor should be made private. Never allow a user to call the constructor on a Singleton; only permit the static instance method to do that.
Actually, with a Singleton, the constructor should be made private. Never allow a user to call the constructor on a Singleton; only permit the static instance method to do that.
I think we will remain in disagreement about that.
Your approach (which matches many tutorials on the subject) is slightly more complicated than my first example in this thread but subject to all the same constraints as that first example.
Sometimes that approach simply doesn't fit the problem. The method I gave in my second example is often the best method. Any time you give a programmer a more flexible method, that provides both the opportunity to make more mistakes and the opportunity to handle more situations. I almost always disagree with rigid rules (as I think you gave above) that prevent unlikely errors while making likely situations hard to solve.
#include "btle.h"
btle* btle::m_instance = NULL;
btle::btle(void)
{
}
btle* btle::instance(QextSerialPort *passedVcp)
{
if (!m_instance) // Only allow one instance of class to be generated.
m_instance = new btle;
btVcp = passedVcp;
return m_instance;
}
void btle::sendBTLEMessage(quint8 len1,char *d1,quint8 len2,char *d2)
{
unsigned int i;
unsigned int j;
char DataOut[200];
i = 1;
for (i=0;i<len1;i++)
DataOut[i] = *d1++;
j = i;
for (i=0;i<len2;i++)
DataOut[i+j] = *d2++;
btVcp->writeData(&DataOut[0],(len1+len2));
}
At some point I managed to get this to compile with
QextSerialPort *btVcp;
...in the header file. I had to put it after the #defines and before the class definition. I then tried to use the singleton, but couldn't do that without getting the same errors as before.
So, I am stuck on:
1. Where to put QextSerialPort *btVcp; I just don't see why I can't put it in the class definition. I get this error if try that:
Code:
/home/robertw/Software/Qt4/BLED112-build-desktop-Qt_in_PATH_Debug/../BLED112/btle.h:24: error: invalid use of member 'btle::btVcp' in static member function
Maybe it's something to do with this whole singleton thing. I can declare it in the instance part of the class, but then, of course, the sendBTLEMessage can't see it.
Now ff I put it after the #defines and before the class definition I get an error saying multiple definitions of btVcp.
2. Even if I get it to compile, how do I access the sendBTLEMessage function? Do I put the C function below:
I have had a tutorial from my friend on singletons and looked up some stuff on-line. I created the following:
I hope that is OK, but I wouldn't bet on it. To answer that better is why I asked question #2 in my post #11. If your program already constructed the object containing sendBTLEMessage, then this common approach to a singleton must be used instead of the ordinary construction. If there was already a correct construction of the object, then the singleton approach I suggested in post #11 is better.
Your use of a parameter in instance() is unusual and I think a bad design. You also seem to be saying btVcp is a global, which I think is a terrible idea.
I'm a bit lost on where the value to be stored into btVcp comes from (and under what conditions it changes), which would affect the way it should be declared and initialized.
So far as the specific error you quoted when you tried making btVcp a member of btle, that would be easy. Instead of:
Code:
btVcp = passedVcp;
use
Code:
m_instance->btVcp = passedVcp;
But I fear that is just adding a patch over a significant design error. I don't think it is good design to have the instance function take a parameter at all.
You never explicitly said what class originally contained sendBTLEMessage, nor what that class was derived from. But the error message you showed in post #5 strongly hints that class was derived from MainWindow. If that was the case then you have now detoured very far from a reasonable path.
If you created a new singleton class and moved sendBTLEMessage into that class, I think you are missing the point. I suspect sendBTLEMessage was originally in the right class and had reason to be there. (Still based on guesses for details you haven't provided) I think the thing to do was to change that class to be a singleton.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.