LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-02-2013, 09:48 AM   #1
DiBosco
Member
 
Registered: Nov 2001
Location: Manchester, UK
Distribution: Mageia
Posts: 807

Rep: Reputation: 40
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.

Code:
extern "C" void SendData(unsigned char l1, char* d1, unsigned char l2, char* d2)
{

    SendBTLEData(l1,d1,l2,d2);

}
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?

Thanks.

Last edited by DiBosco; 03-03-2013 at 06:09 AM.
 
Old 03-02-2013, 10:18 AM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,781

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by DiBosco View Post
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:
Code:
ClassName::SendBTLEData(l1, d1, l2, d2);
 
Old 03-02-2013, 10:25 AM   #3
DiBosco
Member
 
Registered: Nov 2001
Location: Manchester, UK
Distribution: Mageia
Posts: 807

Original Poster
Rep: Reputation: 40
Yes, it is. I will try that. Got to go out now. Thanks a lot.
 
Old 03-02-2013, 10:32 AM   #4
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
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 View Post
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:
Code:
class X {
public:
    static X& singleton() {
        static X the_only_one;
        return the_only_one; }
    void SendBTLEData(unsigned char l1, char* d1, unsigned char l2, char* d2);
private:
    X() : ... { ... }
...
};
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.

You would call that function using
Code:
extern "C" void SendData(unsigned char l1, char* d1, unsigned char l2, char* d2)
{

    X::singleton().SendBTLEData(l1,d1,l2,d2);

}
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.

Last edited by johnsfine; 03-02-2013 at 11:03 AM.
 
Old 03-03-2013, 06:36 AM   #5
DiBosco
Member
 
Registered: Nov 2001
Location: Manchester, UK
Distribution: Mageia
Posts: 807

Original Poster
Rep: Reputation: 40
OK, to answer your question first.

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.

Hope that makes more sense now. Many thanks.
 
Old 03-03-2013, 07:44 AM   #6
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by DiBosco View Post
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
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.

Last edited by johnsfine; 03-03-2013 at 07:49 AM.
 
Old 03-03-2013, 07:50 AM   #7
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by DiBosco View Post
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.
 
Old 03-03-2013, 08:01 AM   #8
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by dwhitney67 View Post
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.
 
Old 03-03-2013, 08:18 AM   #9
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by johnsfine View Post
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.
 
Old 03-03-2013, 10:51 AM   #10
DiBosco
Member
 
Registered: Nov 2001
Location: Manchester, UK
Distribution: Mageia
Posts: 807

Original Poster
Rep: Reputation: 40
Quote:
Originally Posted by johnsfine View Post
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 View Post
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.
Spot on!
 
Old 03-03-2013, 11:08 AM   #11
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
A few basic questions about your class:

1) Does it have a constructor defined?

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.

in hpp file
Code:
class X {
public:
   static X& singleton() { return *the_only_one; }
   X(...);  // declare constructor
private:
   static X* the_only_one;
   ...
};
in cpp file
Code:
X* X::the_only_one = 0;
X::X(...) : ... {  //define constructor
   if ( the_only_one ) { error_out }
   the_only_one = this;
   ...
}
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.

Last edited by johnsfine; 03-03-2013 at 11:42 AM.
 
Old 03-03-2013, 12:27 PM   #12
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
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.

Code:
class Singleton
{
public:
    static Singleton& instance();

    void someNonStaticMethod();

private:
    Singleton();

    static Singleton* theInstance;
};

Singleton::Singleton* theInstance = 0;

Singleton&
Singleton::instance()
{
    if (theInstance == 0)
    {
        theInstance = new Singleton;
    }
    return *theInstance;
}

Singleton::Singleton()
{
}

void
Singleton::someNonStaticMethod()
{
}

int main()
{
    Singleton::instance().someNonStaticMethod();
}
 
Old 03-03-2013, 01:06 PM   #13
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by dwhitney67 View Post
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.
 
Old 03-03-2013, 01:40 PM   #14
DiBosco
Member
 
Registered: Nov 2001
Location: Manchester, UK
Distribution: Mageia
Posts: 807

Original Poster
Rep: Reputation: 40
I'm chasing my tail here.

So, I have had a tutorial from my friend on singletons and looked up some stuff on-line. I created the following:

btle.h

Code:
#ifndef BTLE_H
#define BTLE_H

#include "qextserialport.h"
#include "qextserialbase.h"
#ifdef LINUX
#include "posix_qextserialport.h"
#endif
#ifdef WINDOWS
#include "win_qextserialport.h"
#endif

class btle
{

public:

    static btle* instance(QextSerialPort *passedVcp);
    void sendBTLEMessage(quint8 len1,char *d1,quint8 len2,char *d2);


private:

    btle();
    static btle* m_instance;

};

#endif // BTLE_H
btle.cpp

Code:
#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:

Code:
extern "C" void SendData(unsigned char l1, char* d1, unsigned char l2, char* d2)
{

}
In MainWindow still? Or should I put this in the singleton? And wherever it is out, how does that then call sendBTLEMessage?

Thanks again.
 
Old 03-03-2013, 02:00 PM   #15
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
I haven't read every detail of your post, but your main question is simple:
Quote:
Originally Posted by DiBosco View Post
how do I access the sendBTLEMessage function? Do I put the C function below:

Code:
extern "C" void SendData(unsigned char l1, char* d1, unsigned char l2, char* d2)
{

}

Code:
extern "C" void SendData(unsigned char l1, char* d1, unsigned char l2, char* d2)
{
     btle::instance( ??? )->sendBTLEMessage( ... );
}
Quote:
Originally Posted by DiBosco View Post
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.

Last edited by johnsfine; 03-03-2013 at 02:21 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Calling a function in 1 sec without using any timer based function/API barunparichha Linux - Software 3 09-09-2011 02:15 PM
calling a function every 1 second soltanloo Programming 12 07-25-2009 11:15 AM
calling a function from within another function in php jayakrishnan Programming 2 06-19-2007 08:36 AM
Question for calling function harrylee2003 Programming 3 08-06-2006 07:04 AM
Calling another function from a function using GTK geminigal Programming 4 07-11-2005 03:15 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:51 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration