Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

merge C callbacks into C++ class?

155 views
Skip to first unread message

Lane

unread,
Jun 2, 2015, 1:01:34 AM6/2/15
to
I'm using a C api within the C++ MyClass. This works, but I'd like to be
able to use the private fields (varX) within these callbacks. Is there
anyway to make the callbacks look like class member functions?

Currently, things look like the following.

// file1.cpp
void read_callback(Dev *dev, const MyData *t)
{
// do stuff ...
}

// file2.cpp
class MyClass
{
private:
Dev *dev;
DevListener dl;

// how to use these in the callback?
int var1;
long var2;
string var3;
double var4;

public:
MyClass();
~MyClass();

void operator()() {

try {

dl.listener = read_callback;

ret = Dev_addListener(dev, &dl);
// ...

ret = Dev_start_async_reads(dev);
// ...
}
catch (const exception& e) {
// exception
}
}
};

Lőrinczy Zsigmond

unread,
Jun 2, 2015, 1:22:27 AM6/2/15
to
On 2015.06.02. 7:03, Lane wrote:
> I'm using a C api within the C++ MyClass. This works, but I'd like to be
> able to use the private fields (varX) within these callbacks. Is there
> anyway to make the callbacks look like class member functions?

If the caller of the callback is passing a 'user-parameter'
to the callback, then a static method might work:
the user-parameter will be the address of the object.

Example (with Hungarian comments):
http://web.axelero.hu/lzsiga/cback.cc

Paavo Helde

unread,
Jun 2, 2015, 1:56:51 AM6/2/15
to
Lane <software.resea...@gmail.com> wrote in news:mkjda812947
@news3.newsguy.com:

> I'm using a C api within the C++ MyClass. This works, but I'd like to be
> able to use the private fields (varX) within these callbacks. Is there
> anyway to make the callbacks look like class member functions?

(1) You can declare callback functions as friends.

(2) You can add public member functions to your class which are called by
the callback functions. A bit more tedious, but clearer in the long run.

The drawback with (2) is that these member functions are typically not
really "public". A way to cope with that is to add comments like

public: // implementation

and use some naming schema like Foo_impl() in the method names to indicate
these are not to be called willy-nilly.

The static member function approach suggested by another poster is similar
to (1), but a bit unportable (the static member function linkage may or may
not be compatible with the C linkage assumed by the C API). To be fully
portable one needs to use extern "C" callback functions with a C API, and
(static) member functions cannot be declared extern "C".

Cholo Lennon

unread,
Jun 2, 2015, 8:44:42 AM6/2/15
to
On 06/02/2015 02:56 AM, Paavo Helde wrote:

> The static member function approach suggested by another poster is similar
> to (1), but a bit unportable (the static member function linkage may or may
> not be compatible with the C linkage assumed by the C API). To be fully
> portable one needs to use extern "C" callback functions with a C API, and
> (static) member functions cannot be declared extern "C".
>

Could you explain a bit more about portability problems? I've always
used static member functions as C library callbacks...

TIA



--
Cholo Lennon
Bs.As.
ARG

Martin Shobe

unread,
Jun 2, 2015, 9:57:41 AM6/2/15
to
I don't know of any implementations that do this, but one could have an
implementation that uses one calling convention, say everything on the
stack, for extern "C" functions while the static member functions use a
different one, say the first three in registers with the rest on the
stack. This would cause problems when attempting to call the static
member function from C library. For the example, the first three
arguments would be whatever happened to be in those registers at the
time of the call, the fourth parameter would contain the first
parameter's data[1], etc.

Martin Shobe

[1] This isn't exactly right. We might have objects of different sizes
that keep them from lining up so nicely. You should still get the idea
of why it's not portable to use static member functions as C library
callbacks.

Richard

unread,
Jun 2, 2015, 1:48:32 PM6/2/15
to
[Please do not mail me a copy of your followup]

Lane <software.resea...@gmail.com> spake the secret code
<mkjda...@news3.newsguy.com> thusly:

>I'm using a C api within the C++ MyClass. This works, but I'd like to be
>able to use the private fields (varX) within these callbacks. Is there
>anyway to make the callbacks look like class member functions?

C style callback APIs usually have a void* parameter named something
like "user context" that is registered with the callback function.
This opaque pointer value will be passed to the callback function when
it is invoked.

The typical adaptation of this to a C++ class is to have the class
delcare a static method and register the static method as the callback
with the 'this' pointer as the context argument. The static method
casts the void* user context pointer back to the appropriate type and
then immediately delegates to an instance method.

The static method does not have to be declared extern "C" because
noone is linking to it from a C source file; it is linked within a C++
source file.

Example:

==== Makefile
callback: callback.o main.o
g++ -o callback $^

main.c: callback.h
callback.cpp: callback.h

==== callback.h
#if !defined(CALLBACK_H)
#define CALLBACK_H

typedef void callback_fn_t(void *context);

#if defined(__cplusplus)
extern "C"
{
#endif
extern void register_callback(callback_fn_t *cb, void *user);
extern void register_user_callbacks();

#if defined(__cplusplus)
}
#endif

#endif

==== main.c
#include "callback.h"

callback_fn_t *callback;
void *context;

void register_callback(callback_fn_t *cb, void *user)
{
callback = cb;
context = user;
}

int main()
{
register_user_callbacks();
(*callback)(context);
return 0;
}

==== callback.cpp
#include "callback.h"
#include <iostream>

namespace
{

class Callback
{
public:
void register_callbacks();

private:
static void callback_handler(void *context);

void callback();
};

void Callback::register_callbacks()
{
register_callback(callback_handler, this);
}

void Callback::callback_handler(void *context)
{
static_cast<Callback *>(context)->callback();
}

void Callback::callback()
{
std::cout << "The callback was invoked.\n";
}

Callback long_lived_object;

} // namespace

extern "C"
void register_user_callbacks()
{
long_lived_object.register_callbacks();
}
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Richard

unread,
Jun 2, 2015, 1:52:18 PM6/2/15
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<XnsA4AD5AFEE74C6m...@216.166.105.131> thusly:

>Lane <software.resea...@gmail.com> wrote in news:mkjda812947
>@news3.newsguy.com:
>
>> I'm using a C api within the C++ MyClass. This works, but I'd like to be
>> able to use the private fields (varX) within these callbacks. Is there
>> anyway to make the callbacks look like class member functions?
>
>(1) You can declare callback functions as friends.

Please god, no. Friend use is abuse most of the time and it is not
needed to handle C callbacks and shouldn't be the *first* thing
mentioned in a list of alternatives.

>(2) You can add public member functions to your class which are called by
>the callback functions. A bit more tedious, but clearer in the long run.

It isn't necessary to add public member functions in order to use C
style callbacks as my earlier example demonstrates. Usually a single
class acts as the receiver of callback messages from a C api and
registers itself with the API. The registered callback functions
don't have to be public and probably shouldn't be public because the
callback mechanism is an internal implementation detail and not part
of the public interface of this class. C mish-mashes implementation
and interface all together most of the time, so it's nearly impossible
to see this when looking at C code.

>The static member function approach suggested by another poster is similar
>to (1), but a bit unportable (the static member function linkage may or may
>not be compatible with the C linkage assumed by the C API).

This is just plain wrong; you don't understand how the linkage is
working in this case. There is no C code linking explicitly to your
callback functions, they only appear inside a C++ linkage context.

Paavo Helde

unread,
Jun 2, 2015, 2:09:56 PM6/2/15
to
Cholo Lennon <cholo...@hotmail.com> wrote in
news:mkk8ff$p3o$4...@speranza.aioe.org:
Yes, there appears to be no problem with most (all?) existing C++
implementations and all new implementations will probably have to follow
the suite too to avoid breaking tons of code. Nevertheless, this approach
is not guaranteed to work by the standard because C functions and C++
static member functions are not guaranteed to use the same calling
conventions.

Some compilers like MSVC have extensions for specifying calling conventions
also for static member functions. One can e.g. declare a __stdcall static
member function which can then be used as a callback function with certain
Windows SDK functions. These extensions are of course non-portable as well.

Paavo Helde

unread,
Jun 2, 2015, 2:13:55 PM6/2/15
to
legaliz...@mail.xmission.com (Richard) wrote in
news:mkkqg9$uik$2...@news.xmission.com:

> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <XnsA4AD5AFEE74C6m...@216.166.105.131> thusly:
>
>>The static member function approach suggested by another poster is
>>similar to (1), but a bit unportable (the static member function
>>linkage may or may not be compatible with the C linkage assumed by the
>>C API).
>
> This is just plain wrong; you don't understand how the linkage is
> working in this case. There is no C code linking explicitly to your
> callback functions, they only appear inside a C++ linkage context.

This is not about name mangling when linking, this is about the calling
conventions. The extern "C" thingy affects both in principle.

Paavo Helde

unread,
Jun 2, 2015, 2:23:14 PM6/2/15
to
Paavo Helde <myfir...@osa.pri.ee> wrote in
news:XnsA4ADD7F1A4724m...@216.166.105.131:
This is also covered by a FAQ:
https://isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr

"Note: static member functions do not require an actual object to be
invoked, so pointers-to-static-member-functions are usually type-
compatible with regular pointers-to-functions. However, although it
probably works on most compilers, it actually would have to be an extern
"C" non-member function to be correct, since “C linkage” doesn’t only
cover things like name mangling, but also calling conventions, which
might be different between C and C++."



Ian Collins

unread,
Jun 2, 2015, 3:00:50 PM6/2/15
to
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <XnsA4AD5AFEE74C6m...@216.166.105.131> thusly:
>
>> Lane <software.resea...@gmail.com> wrote in news:mkjda812947
>> @news3.newsguy.com:
>>
>>> I'm using a C api within the C++ MyClass. This works, but I'd like to be
>>> able to use the private fields (varX) within these callbacks. Is there
>>> anyway to make the callbacks look like class member functions?
>>
>> (1) You can declare callback functions as friends.
>
> Please god, no. Friend use is abuse most of the time and it is not
> needed to handle C callbacks and shouldn't be the *first* thing
> mentioned in a list of alternatives.

A friend, declared extern "C", is the only guaranteed portable means to
implement a C callback in a C++ class.

I guess most people use g++ or other compilers that don't complain about
static members having the wrong linkage, but some do.

--
Ian Collins

Marcel Mueller

unread,
Jun 2, 2015, 3:03:42 PM6/2/15
to
On 02.06.15 20.23, Paavo Helde wrote:
> "Note: static member functions do not require an actual object to be
> invoked, so pointers-to-static-member-functions are usually type-
> compatible with regular pointers-to-functions. However, although it
> probably works on most compilers, it actually would have to be an extern
> "C" non-member function to be correct, since C linkage doesn t only
> cover things like name mangling, but also calling conventions, which
> might be different between C and C++."

With IBM VAC++ you cannot use static members with C callbacks since C++
functions /always/ pass the first parameters in registers.

With g++ in contrast it is almost impossible to use -mregparm because it
breaks the runtime library calls. While the public functions like strlen
could be covered by appropriate header files, internal calls, e.g. for
memory allocation of operator new will sadly fail. Not using register
parameters makes the executables unnecessarily large, but you can use
static members a C callbacks.


Marcel

Chris Vine

unread,
Jun 2, 2015, 3:43:24 PM6/2/15
to
§7.5/1 of C++11:

"All function types, function names with external linkage, and
variable names with external linkage have a language linkage. ... The
default language linkage of all function types, function names, and
variable names is C++ language linkage. Two function types with
different language linkages are distinct types even if they are
otherwise identical."

The particular point about language linkage of functions is that those
with C++ linkage may have a different calling convention than functions
with C linkage (say, about whether arguments are passed on the stack or
in registers and about whether the caller or callee is responsible for
resetting stack pointers on exit).

As it happens, gcc and clang use the same calling convention for static
member functions and for plain functions. But as mentioned in the
extract from the standard above, that is not a requirement of the
standard, and ICC is reputed not to do so (but I have never tested
that).

Chris

Richard

unread,
Jun 2, 2015, 7:04:36 PM6/2/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<ct6cqj...@mid.individual.net> thusly:
It *still* doesn't need to be friend. Friend in C++ is the unix
equivalent of "run all my servers as root".

Richard

unread,
Jun 2, 2015, 7:08:13 PM6/2/15
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<XnsA4ADD7F1A4724m...@216.166.105.131> thusly:
Yes, I can see that calling conventions may be an issue and that
extern "C" can affect calling conventions used for a function.

If you're dealing with any significant amount of C callback junk in
your C++ application, you're better off putting a real abstraction
around it (like an interface) and creating a delegating layer that
marshalls between C callbacks and your C++ abstraction.

Remember, C does callbacks with function pointers because it has no
other means of representing abstraction and polymorphism. As always,
strive to keep these C habits out of your C++ code and confine them to
a small fenced-in area in the corner of the back yard where they won't
poop on your lawn.

red floyd

unread,
Jun 2, 2015, 7:58:17 PM6/2/15
to
What would be really nice is to be able to declare static member
functions with C linkage

e.g.:

class callback_t
{
static "C" callback(void *p) // not currently valid syntax
{
static_cast<callback_t *>(p)->handler();
}
void handler();
public:
register_callback()
{
some_C_api(&callback,this);
}
};



Öö Tiib

unread,
Jun 3, 2015, 8:19:53 AM6/3/15
to
On Wednesday, 3 June 2015 02:04:36 UTC+3, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <ct6cqj...@mid.individual.net> thusly:
>
> >Richard wrote:
> >> [Please do not mail me a copy of your followup]
> >>
> >> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> >> <XnsA4AD5AFEE74C6m...@216.166.105.131> thusly:
> >>
> >>> Lane <software.resea...@gmail.com> wrote in news:mkjda812947
> >>> @news3.newsguy.com:
> >>>
> >>>> I'm using a C api within the C++ MyClass. This works, but I'd like to be
> >>>> able to use the private fields (varX) within these callbacks. Is there
> >>>> anyway to make the callbacks look like class member functions?
> >>>
> >>> (1) You can declare callback functions as friends.
> >>
> >> Please god, no. Friend use is abuse most of the time and it is not
> >> needed to handle C callbacks and shouldn't be the *first* thing
> >> mentioned in a list of alternatives.
> >
> >A friend, declared extern "C", is the only guaranteed portable means to
> >implement a C callback in a C++ class.
> >
> >I guess most people use g++ or other compilers that don't complain about
> >static members having the wrong linkage, but some do.
>
> It *still* doesn't need to be friend. Friend in C++ is the unix
> equivalent of "run all my servers as root".

Is there really such a difference between static member and friend
function?

I imagine something like that:

// With friend
class friendly
{
friend extern "C" void callback_friendly(void *p)
{
// do what it got to do
}

public:
register_callback()
{
some_C_api(&callback_friendly,this); // conforming
}

// ... rest of the class
};

// With static
class statical
{
static void callback_statical(void *p)
{
// do exactly same things like the 'friendly' did
}

public:
register_callback()
{
some_C_api(&callback_statical,this); // conformance missing
// but often works
}

// ... rest of the class
};

Might be there are some nuances I miss. Can you elaborate what is
the important problem?

Öö Tiib

unread,
Jun 3, 2015, 8:37:48 AM6/3/15
to
On Tuesday, 2 June 2015 20:48:32 UTC+3, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Lane <software.resea...@gmail.com> spake the secret code
> <mkjda...@news3.newsguy.com> thusly:
>
> >I'm using a C api within the C++ MyClass. This works, but I'd like to be
> >able to use the private fields (varX) within these callbacks. Is there
> >anyway to make the callbacks look like class member functions?
>
> C style callback APIs usually have a void* parameter named something
> like "user context" that is registered with the callback function.
> This opaque pointer value will be passed to the callback function when
> it is invoked.
>
> The typical adaptation of this to a C++ class is to have the class
> delcare a static method and register the static method as the callback
> with the 'this' pointer as the context argument. The static method
> casts the void* user context pointer back to the appropriate type and
> then immediately delegates to an instance method.
>
> The static method does not have to be declared extern "C" because
> noone is linking to it from a C source file; it is linked within a C++
> source file.

Your code example assumes that there are no difference between:

typedef void callback_fn_t(void *context);

and

extern "C" typedef void callback_fn_t(void *context);

It is so with gcc, but nothing guarantees that in C++ standard.

Chris Vine

unread,
Jun 3, 2015, 1:04:39 PM6/3/15
to
On Tue, 02 Jun 2015 16:58:08 -0700
red floyd <no....@its.invalid> wrote:
> On 6/2/2015 12:43 PM, Chris Vine wrote:
[snip]
> > §7.5/1 of C++11:
> >
> > "All function types, function names with external linkage, and
> > variable names with external linkage have a language
> > linkage. ... The default language linkage of all function types,
> > function names, and variable names is C++ language linkage. Two
> > function types with different language linkages are distinct types
> > even if they are otherwise identical."
> >
> > The particular point about language linkage of functions is that
> > those with C++ linkage may have a different calling convention than
> > functions with C linkage (say, about whether arguments are passed
> > on the stack or in registers and about whether the caller or callee
> > is responsible for resetting stack pointers on exit).
> >
> > As it happens, gcc and clang use the same calling convention for
> > static member functions and for plain functions. But as mentioned

By "plain functions" I of course meant "plain functions with C language
linkage".

> > in the extract from the standard above, that is not a requirement
> > of the standard, and ICC is reputed not to do so (but I have never
> > tested that).
>
> What would be really nice is to be able to declare static member
> functions with C linkage
>
> e.g.:
>
> class callback_t
> {
> static "C" callback(void *p) // not currently valid syntax
> {
> static_cast<callback_t *>(p)->handler();
> }
> void handler();
> public:
> register_callback()
> {
> some_C_api(&callback,this);
> }
> };

It would be nice but there is a technical problem in doing this, which
is that giving a function C language linkage suppresses name mangling:
a requirement of C language linkage is that the function concerned
should be callable by name (not just by function pointer) by C code
expecting C language linkage. If two unrelated classes could have
static member functions of the same name both of which are declared to
have C language linkage, then there would be a name clash.

Chris

Chris Vine

unread,
Jun 3, 2015, 1:04:39 PM6/3/15
to
On Tue, 2 Jun 2015 23:04:27 +0000 (UTC)
legaliz...@mail.xmission.com (Richard) wrote:
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <ct6cqj...@mid.individual.net> thusly:
[snip]
> >A friend, declared extern "C", is the only guaranteed portable means
> >to implement a C callback in a C++ class.
> >
> >I guess most people use g++ or other compilers that don't complain
> >about static members having the wrong linkage, but some do.
>
> It *still* doesn't need to be friend. Friend in C++ is the unix
> equivalent of "run all my servers as root".

You could say exactly the same of a public member function (static or
non-static). Friend functions are the only portable way of
implementing callback functions with C language linkage which require
access to private or protected members of a class.

The main problem with the declaration of a friend function is that you
have to declare it together with the class definition, which means that
you cannot confine it to the implementation (.cc/.cpp) file and give it
internal linkage where that would otherwise be possible. The same is
equally true of course of static and non-static member functions.

Chris

Martin Shobe

unread,
Jun 3, 2015, 1:18:40 PM6/3/15
to
Is it anymore of a problem than it currently is with namespaces?

Martin Shobe

Scott Lurndal

unread,
Jun 3, 2015, 1:35:46 PM6/3/15
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
>On Tue, 2 Jun 2015 23:04:27 +0000 (UTC)
>legaliz...@mail.xmission.com (Richard) wrote:
>> Ian Collins <ian-...@hotmail.com> spake the secret code
>> <ct6cqj...@mid.individual.net> thusly:
>[snip]
>> >A friend, declared extern "C", is the only guaranteed portable means
>> >to implement a C callback in a C++ class.
>> >
>> >I guess most people use g++ or other compilers that don't complain
>> >about static members having the wrong linkage, but some do.
>>
>> It *still* doesn't need to be friend. Friend in C++ is the unix
>> equivalent of "run all my servers as root".
>
>You could say exactly the same of a public member function (static or
>non-static). Friend functions are the only portable way of
>implementing callback functions with C language linkage which require
>access to private or protected members of a class.

I disagree.

extern "C" void callback_function(void *arg);


void
callback_function(void *arg)
{
Classname *classpointer = static_cast<Classname *>(arg);

classpointer->callback();
}

c_library_function_register_callback(callback_function, this);

portable yet friendless.

Chris Vine

unread,
Jun 3, 2015, 5:41:16 PM6/3/15
to
You do not disagree. Classname::callback() must be public for this to
work. If Classname::callback() were protected or private,
callback_function() would need to be a friend.

Chris

Chris Vine

unread,
Jun 3, 2015, 5:50:37 PM6/3/15
to
Not with named namespaces. As you suggest, a named namespace is ignored
for any function declared within the namespace with C language linkage,
leading (for those who don't know that) to the possibility of name
clashes between such functions declared with the same name within
different namespaces. However, in C++11/14 (but not C++98/03), unnamed
namespaces are effective for functions with C linkage in enforcing
internal linkage (that is, it has the same effect as applying the
static keyword).

The lesson: in C++11/14 do not declare functions within a named
namespace with C language linkage; and with C++98/03 don't do it within
an unnamed namespace either.

However, I was answering a question about why static member functions
cannot have C language linkage.

Chris



0 new messages