473,785 Members | 3,134 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Mixing C library code and callbacks with C++ Classes

I have a library which was written in C, you call a function, it
provides the result by a callback to specific function names. I am
trying to wrap the calls to this inside a class, but this causes a
problem with the callbacks, for example:

class X {
public:
add();
};

X::add() {
library_add(1,2 );
}

library_add will return the result by calling add_result(int) callback.
I need this function inside the class, but then it cannot be seen, and
I get linker errors; I have to have the add_result outside of the
class, but then it has no access to the internals of the class.

Ideally, it would be like this

class X {
public:
add();
add_result();
private:
sum;
};

X::add() {
library_add(1,2 );
}

X::add_result(i nt a) {
sum+=a;
}

/*
In reality, I have to do this but then I can
only have one instance of the object working

X *pointer_to_an_ x_instance;
X::X() {
pointer_to_an_x _instance = this;
}

//add_result is NOT a member method
add_result(int a) {
pointer_to_an_x _instence->inc_sum(a);
}
*/

Obviously this is just a little example I made up, rather than
involving the whole complexities of the real library.

Can somebody explain if, and how I can achieve it and be fully object
oriented.

Jul 22 '05 #1
4 3374
On Tue, 7 Dec 2004 wo************* *@yahoo.com wrote:
I have a library which was written in C, you call a function, it
provides the result by a callback to specific function names. I am
trying to wrap the calls to this inside a class, but this causes a
problem with the callbacks, for example:

class X {
public:
add();
};

X::add() {
library_add(1,2 );
}

library_add will return the result by calling add_result(int) callback.
I need this function inside the class, but then it cannot be seen, and
I get linker errors; I have to have the add_result outside of the
class, but then it has no access to the internals of the class.

Ideally, it would be like this

class X {
public:
add();
add_result();
private:
sum;
};

X::add() {
library_add(1,2 );
}

X::add_result(i nt a) {
sum+=a;
}

/*
In reality, I have to do this but then I can
only have one instance of the object working

X *pointer_to_an_ x_instance;
X::X() {
pointer_to_an_x _instance = this;
}

//add_result is NOT a member method
add_result(int a) {
pointer_to_an_x _instence->inc_sum(a);
}
*/

Obviously this is just a little example I made up, rather than
involving the whole complexities of the real library.

Can somebody explain if, and how I can achieve it and be fully object
oriented.


did you do for your c routines
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "my_c_routines. h"
#ifdef __cplusplus
}
#endif

Put this in your c head files. I believe it prevents name mangling.

___ _ ____ ___ __ __
/ _ )(_) / /_ __ / _ \___ _/ /_/ /____ ___
/ _ / / / / // / / ___/ _ `/ __/ __/ _ \/ _ \
/____/_/_/_/\_, / /_/ \_,_/\__/\__/\___/_//_/
/___/
Texas Instruments ASIC Circuit Design Methodology Group
Dallas, Texas, 214-480-4455, b-******@ti.com
Jul 22 '05 #2
<wo************ **@yahoo.com> wrote in message
news:11******** *************@z 14g2000cwz.goog legroups.com...
I have a library which was written in C, you call a function, it
provides the result by a callback to specific function names. I am
trying to wrap the calls to this inside a class, but this causes a
problem with the callbacks, for example:

[snip]

First of all, I hope you have a good reason to wrap this C library with C++
objects. Sometimes the C libraries have a good object-oriented design (at
least at the interface level), just this design is expressed in a wrong
language (C). If the design is apparent from the library itself, then it
should be straightforward to perform the wrapping. You will recognize such a
design, for example, if there are groups of functions, which are grouped
around particular tasks, where majority of functions from a single group has
something common in the parameters - some opaque pointer to a structure, a
"handle" or something similar. Here is a couple of declarations from zlib,
for example (comments omitted):

ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
....
ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
voidpc buf, unsigned len));
....

As a first attempt, one could wrap all inflate/deflate functions into one
class (which will encapsulate z_streamp), while wrapping all gz... functions
into another class (which will encapsulate gzFile). This may not produce a
terribly good C++ code, but at least the overall class design of this code
won't be worse that the object-oriented design of the original class
library.

Regarding the callbacks: as Greg have noticed, sometimes C libraries provide
a "context" that you specify when registering a callback with the library
(and which you receive in your callback). Similarly, the C library may
return you a "cookie" while registering a callback. This is an additional
sign that the C library creator had an OO design in mind. If it is missing,
then this C library is probably not designed in an OO way.

My point is, actually: look at the C library and try to understand its
design. If it is object-oriented, you can try to wrap it into classes. If it
isn't, you better leave the C library as it is, and directly use it in your
C++ programs. IMHO it is easier for C++ programmers (at least for me!) to
comprehend no object-oriented design from a C library than to comprehend a
bad design from a C++ library.

Finally, to avoid comments that I am talkative without saying anything... if
you lack "context" supplied when registering callbacks, you still can
develop a "connection point", i.e. a Singletone class that can distribute
notifications (a degenerate case of Observer pattern). Something like:

//=============== =============== ====
// library.h
//=============== =============== ====
#ifndef LIBRARY_H
#define LIBRARY_H

extern "C"
{
void library_registe r_add(void (*callback)(int ));
void library_unregis ter_add();
void library_add(int x, int y);
}

#endif /* LIBRARY_H */

//=============== =============== ====
// AddResultCP.h
//=============== =============== ====
#ifndef ADD_RESULT_CP_H
#define ADD_RESULT_CP_H

#include <set>

class AddResultReceiv er;

class AddResultCP
{
public:
static AddResultCP &Instance();

void Register(AddRes ultReceiver *receiver) {
receivers.inser t(receiver); }
void Unregister(AddR esultReceiver *receiver) {
receivers.erase (receiver); }

private:
AddResultCP() { library_registe r_add(AddResult Callback); }
~AddResultCP() { library_unregis ter_add(); }

static void AddResultCallba ck(int result) {
Instance().Noti fyAddResult(res ult); }
void NotifyAddResult (int result);

typedef std::set<AddRes ultReceiver *> ReceiverSet;
ReceiverSet receivers;
};

class AddResultReceiv er
{
protected:
AddResultReceiv er() { Register(); }
virtual ~AddResultRecei ver() { Unregister(); }

void Add(int x, int y) { library_add(x, y); }

void Register() { AddResultCP::In stance().Regist er(this); }
void Unregister() { AddResultCP::In stance().Unregi ster(this); }

private:
friend class AddResultCP;
virtual void AddResult(int result) = 0;
};

#endif // ADD_RESULT_CP_H

//=============== =============== ====
// AddResultCP.cpp
//=============== =============== ====

AddResultCP &AddResultCP::I nstance()
{
static AddResultCP cp;
return cp;
}

void AddResultCP::No tifyAddResult(i nt result)
{
for (ReceiverSet::i terator it = receivers.begin (); it !=
receivers.end() ; ++it)
{
(*it)->AddResult(resu lt);
}
}

To use this approach, one should derive from AddResultReceiv er and implement
AddResult method. Then, she can call Add from the derived class and expect
AddResult to be called when the library prepares the result. Of course, this
is not a very polished C++ code, but it illustrates a possible approach.

Beware of:

(1) although Add is invoked on a single AddResultReceiv er object, ALL
registered AddResultReceiv er objects will receive the result (this is
actually a biggest problem in this approach, but sometimes you can't do
better),
(2) reentrancy (your AddResult method may be called in the middle of your
Add method),
(3) threading issues if you work on a multithreaded platform,
(4) temptation to add much functionality to the above classes. They should
serve just as an interface between C library and its C++ users - the real
job is performed by the users.

I don't know whether this suits your needs - I hope it may help.

Regards,
Rade
Jul 22 '05 #3

wo************* *@yahoo.com wrote:
I have a library which was written in C, you call a function, it
provides the result by a callback to specific function names.
Be aware that this is /not/ what the rest of the world means when
they talk about callbacks. What they mean is passing the /address/
of a function /at runtime/.

This means that the "stock C++ reply to callbacks" won't work here.
( which would be, use a static member function - won't work here)
I am trying to wrap the calls to this inside a class, but this
causes a problem with the callbacks, for example:

class X {
public:
add();
};

X::add() {
library_add(1,2 );
}

library_add will return the result by calling add_result(int) callback. I need this function inside the class, but then it cannot be seen, and I get linker errors; I have to have the add_result outside of the
class, but then it has no access to the internals of the class.
Wrong assumption - friends are outside the class but can access
the internals - provided they know /which/ object they have to look in.
Same goes for any OO function, they all need objects. Usually on the
left hand side of a . but that's just convention.
In reality, I have to do this but then I can
only have one instance of the object working

X *pointer_to_an_ x_instance;
X::X() {
pointer_to_an_x _instance = this;
}

//add_result is NOT a member method
add_result(int a) {
pointer_to_an_x _instence->inc_sum(a);
}
*/

Obviously this is just a little example I made up, rather than
involving the whole complexities of the real library.


Another solution is
stack<X*> pointer_to_x_in stances;
X::add()
pointer_to_x_in stances.push(th is);
library_add(1,2 );
pointer_to_x_in stances.pop();
}
//add_result is NOT a member method
add_result(int a) {
X* that = pointer_to_x_in stances.top();
that->do_add_result( a);
}

It's even reentrant with its own stack. Still, this is not
really OO. There are just things that can't be fixed. This one
qualifies, a bad C design makes even worse C++.
Regards,
Michiel Salters

Jul 22 '05 #4
That looks like the kind of system I am going to use, although looking
at it, I dont think I need that stack; as the whole thing is
sequential, it would be simple enough to have a global pointer that is
set before the library_add then unset afterwards, which is basically
what is happening at the top of stack? (What I am trying to say, is
that pointer_t_x_ins tances will never end up having more than 1
instance).

Thank you for all the ideas and information, it's been a great help.
Regarding the C library, that was written by somebody else, it has no
idea of registering contexts, from the limited documents it states that
one is required to provide these functions with the specifc names, no
options, they must just exist in the module.

To me, object oriented code is the norm, and makes more sense, which is
why I am trying to maintain something along those lines - the rest of
my system is object oriented.

Jul 22 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1829
by: Erik Max Francis | last post by:
Is there any prohibition against mixing different protocols within the same pickle? I don't see anything about this in the Python Library Reference and, after all, the pickle.dump function takes a protocol argument for each time it's called. (This is in Python 2.3.3.) I have a pickle containing two objects: a tag string and a (large) object containing many children. The identifying string is there so that you can unpickle it and...
4
23691
by: Rudolf | last post by:
Is it possible to add a vb.net source code module to a c# project and if so how? Thanks Rudolf
1
285
by: womanontheinside | last post by:
I have a library which was written in C, you call a function, it provides the result by a callback to specific function names. I am trying to wrap the calls to this inside a class, but this causes a problem with the callbacks, for example: class X { public: add(); };
18
3040
by: Cameron Laird | last post by:
QOTW: "... So I started profiling the code and the slowdown was actually taking place at places where I didn't expect it." -- Guyon Mor?e (and about twenty-three thousand others) " suggestion from the world of 'agile development': stop making so many decisions and start writing some actual code!" -- Peter Hansen Scott David Daniels and others illustrate that the most common answer for Python is, "It's (already) in there." In the...
9
3345
by: zholthran | last post by:
Hi folks, after reading several threads on this issue (-> subject) I fear that I got a problem that cannot easily be solved by the offered workarounds in an acceptable way, at least not with my limited c & c++ experience. Maybe some of you can help. the problem: I need several instances of a class whose (non-static!) methods should serve as callbacks for a dll (which can' be manipulated/adapted in any
28
3103
by: ziman137 | last post by:
Hello all, I have a question and am seeking for some advice. I am currently working to implement an algorithmic library. Because the performance is the most important factor in later applications, I decide to write it in C instead of C++. However, I thought it might be convenient to use some C++ code at some misc places. I'm aware that, I could always use the C++ compiler to get it work.
5
1721
by: Budde, Marco | last post by:
We have developed a big library using managed C++. The project started with .NET 1.0 and has been ported to .NET 1.1. Today we ship the library compiled for .NET 1.1 and 2.0. At the moment the whole code uses the "old" managed C++ syntax. Due to the amount of code and the need of supporting .NET 1.1 it is not possible for us to port the complete code to the new CLI/C++ syntax. We would like to use the new Generics. We have written a...
1
1463
by: rhossi | last post by:
I have an Assembly using IJW that uses a third party native library. There are quite a few function calls that uses callbacks and pointers. One of those takes a delegate: bool enumXXX(char * someData, unsigned long lparam); Inside the passed delegate I need to cast from unsigned long to List<String^^. How Can I do this ? Thanks,
3
2036
by: rewtedesco | last post by:
I bet that others came across this problem and that there is a very good general solution, however I have not been able to get this done. In short: How to replace std::cout by something that writes in a dialog box without mixing my code with some monstrous class library such as in Qt4, or for Windows Microsoft's class libraries. The details of this implementation should not matter for this question. The only thing that matters is that...
0
10319
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9947
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8971
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7496
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5380
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5511
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4046
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3645
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2877
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.