OOP in C!

  • Thread starter Prashanth Ellina
  • Start date
J

James Hu

Please show an example
where a function pointer is *not* used to implement a callback function.

/* -- example.c -- */

static void example_func_impl(void);
static void example_func_impl_init(void);

static void (*example_func_pointer)(void) = example_func_impl_init;

void example_func(void)
{
example_func_pointer();
}

static void example_func_impl_init(void)
{
/* do some initialization stuff for the first time function is called */
/* ... */

example_func_pointer = example_func_impl;
example_func_impl();
}

static void example_func_impl(void)
{
/* do what the function is supposed to do */
/* ... */
}

-- James
 
T

Thomas Stegen

E. Robert Tisdale said:
Please show an example
where a function pointer is *not* used to implement a callback function.

A callback function is an example of inversion of control,
a function pointer does not necessarily involve inversion of
control. It seems to me that the line is blurry, but a function
pointer is not necessarily a callback function.
 
C

CBFalconer

Christian said:
Since your little brain doesn't have enough braincells to
understand the difference between a function pointer and a
callback function, giving an example to you would be pointless.

If you are familiar with the long running US comedy 'Cheers', you
may remember the various jokes about usage of 'Cliffs brain'. We
have a Trollsdale serving a very similar function.
 
W

Wavemaker

Christian Bau said:
Since your little brain doesn't have enough braincells to
understand the difference between a function pointer and a
callback function, giving an example to you would be
pointless.

I don't really understand the vitriol here (nor am I asking for an
explanation for it either), but I've read through this thread a few
times now and my understanding as it stands is this:

The term "callback" is a label given to a function called indirectly
by being dereferenced via a function pointer. As you've said,
"Callback function" refers to usage. There's nothing really special
about a callback function per se; it's all about intent and usage.
Usually, a callback function is written with a specific use in mind,
as in the qsort example you used, but beyond that a callback
function is simply a normal function.

The callback mechanism is implemented through function pointers. In
other words, the callback function itself is not implemented through
function pointers but rather the means of "calling back" the
function is accomplished through function pointers.

So far, so good?

If I'm on track, the question of when function pointers are used in
a non-callback context is an interesting one, at least to me. I
can't think of any off hand, and I'm not sure I understand the "bit
pattern" example given up thread. That's not to say there aren't any
uses of function pointers outside of a callback mechanism, I just
don't know of any.

As far as the difference between virtual functions used in an object
oriented language and callback functions as they are implemented in
C, seems like the underlying mechanics can be similar but that the
term "callback" is really too low-level to be used in an OOL. Other
than that, I don't have much to say.
 
C

Chris Torek

The term "callback" is a label given to a function called indirectly
by being dereferenced via a function pointer. ...

That is one possible definition of the term "callback function",
but I contend it is not a very good one.
As [someone else] said, "Callback function" refers to usage.

This is a better definition. It is still not all that solid,
though.

A google search suggests that there is no single, fixed definition
in computing. Microsoft have two separate definitions, one for
their Windows API and one for IIS. Erlang defines a callback
function as a (particular kind of) function in a callback module.
All these definitions share a common "flavor", though, and they
all fit at least reasonably well under the "usage" label. I think
we can refine this a bit though, by splitting tasks among particular
"entities", and referring back to the English-language meaning of
"I'll call you back".

Suppose a program is split into two or more "algorithmic entities",
where the responsibility for some particular task is delegated to
some sub-entity. For instance, we might have an application that
interacts with a user, talks to a database, and runs a printer,
all at various times.

Suppose the user code calls the database software, and while that
is doing its job, it encounters a database problem and needs to do
some quick interaction with the user (while still being "mostly
database-y"). It might use a "callback" into the user-interface
code to achieve this.

Later, if the database code decides to run the printer, and the
code running the printer runs into a problem and needs information
from the database (while still being "mostly printer-y"), it might
use a "callback" into the database code. If the answer is "this
requires user interaction", but the database and printer code is
not being called *by* the user-interaction code, then a call from
the database or printer code into the user-interaction code is just
a "call", not a "call back".

There is still a lot of "wool" in this attempt to "define by example",
so let me try a more formal specification. This is just my attempt,
not any sort of "official" definition for a callback function:

A function is labeled "callback" when it is "called back" by
a separate body of code that is called to perform some specific
task. That is, code-group A calls code-group B, and code-group
B does most of the work, but occasionally needs processing by
code-group A. If that extra processing is supplied by having
code-group B call a specified function within code-group A,
the designated function in A is a "callback".
There's nothing really special about a callback function per se;
it's all about intent and usage. Usually, a callback function is
written with a specific use in mind, as in the qsort example you
used, but beyond that a callback function is simply a normal function.
Right.

The callback mechanism is implemented through function pointers.

Not necessarily.

This *is* a useful mechanism, but not the only possible one, even
in C, and in other languages only the alternative mechanisms might
be available.

Let me use a simple quicksort function again as an example. This
quicksort will use the same calling sequence as C's qsort(), except
that the comparison function pointer is omitted. That is, instead
of:

void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));

we have (nb, I just typed this in without testing it, no guarantee
it is correct, and it is not optimized in any way):

void quicksort(void *base, size_t nel, size_t width) {
extern int qcompare(const void *, const void *);
unsigned char *b, *pivot;
unsigned char *l, *r;
size_t i, j, half;

if (nel < 2) /* empty or 1 element => already sorted */
return;
b = base;
i = 0;
j = nel - 1;
/* select "middle" item as pivot, rounding up "just because" */
half = (j + 1) / 2;
pivot = base + half;
partition:
if (i <= j) {
l = base + i * width; /* left-side item */
if (qcompare(l, pivot) < 0) {
i++;
goto partition;
}
r = base + j * width; /* right-side item */
if (qcompare(r, pivot) >= 0) {
j--; /* can get j<i here */
goto partition;
}
if (i < j) {
/* qmemswap saves item l, copies r to l, copies saved to r */
qmemswap(l, r, width);
goto partition;
}
}
/*
* now everything from [0..half) < pivot and everything from
* (half..nel) is >= pivot, and of course pivot == pivot.
* The second interval might be empty.
*/
quicksort(base, half, width);
if (nel - 1 > half)
quicksort(pivot + width, nel - half - 1, width);
}

Here quicksort() "calls back" into whatever called it by calling
the function qcompare() *using the name qcompare*.

To use this version of quicksort, instead of the (no doubt superior)
C library qsort(), you must name your function "qcompare". You
get only one comparison function per C program. But qcompare() is
still a callback function, *even though it is called directly*
(rather than via a pointer).
In other words, the callback function itself is not implemented through
function pointers but rather the means of "calling back" the
function is accomplished through function pointers.

Or, by name -- but using a pointer is "better", because in this
case, it allows us to call qsort() from any number of places, and
use different functions, not just qcompare(), to compare elements.
If I'm on track, the question of when function pointers are used in
a non-callback context is an interesting one, at least to me.

You might find a good example in a state-machine, such as this
skeleton that works with a hardware device:

struct state {
struct state (*next)(struct state);
... other elements if needed ...
};

struct state start(struct state);
struct state stop(struct state);
...
void run_state_machine(void) {
struct state s = { start };
do {
wait_for_hardware_to_be_ready();
s = s.next(s);
} while (s.next != stop);
}
...
struct state start(struct state x) {
if (some_hardware_switch)
x.next = s1;
else
x.next = s2;
return x;
}
...

These do not really qualify as "callbacks" because the entire
machine is all one body of code. Functions start(), s1(), s2(),
s3(), ..., stop() are all provided as a single package, and the
"driver" function -- run_state_machine() -- is permanently attached
to the same package, by virtue of waiting for the hardware in
question before each step.

Of course, you could "re-divide" the task here, so that the state
machine is separate from the hardware-interation. If you did that,
each state-handler *would* suddenly qualify for the "callback"
label. But this is as it should be: if you restructure the code
and move responsibilities around, it becomes different code, using
the same mechanisms for different purposes, so it may well deserve
different labels.
 
M

Malcolm

Wavemaker said:
I don't really understand the vitriol here (nor am I asking for an
explanation for it either), but I've read through this thread a few
times now and my understanding as it stands is this:
We'll spare you that. Some people should be more careful in responding to E.
Robert Tisdale.
The term "callback" is a label given to a function called indirectly
by being dereferenced via a function pointer.
And also passed to a lower level function. Eg qsort() takes a callback
function.
In C it is impossible to place restrictions on functions (eg insist that
they be leaf functions, ban them from performing IO, insist they be pure
functions, etc).
If I'm on track, the question of when function pointers are used
in a non-callback context is an interesting one, at least to me. I
can't think of any off hand, and I'm not sure I understand the "bit
pattern" example given up thread. That's not to say there aren't
any uses of function pointers outside of a callback mechanism, I
just don't know of any.
Generally you would use a function pointer to abstract some of the logic.
For instance qsort() can sort any set of structures because the comparison
is not hard-coded. If you are implementing a hash table you might want
function pointers for retrieving keys, maybe implementing the hash function
itself.
There are a few cases.
let's say we are debugging and we want to know where the compiler is putting
our function in memory.

void print_fptr( void (*fptr)(void))
{
unsigned char pattern[sizeof fptr];
int i;

memcpy(pattern, &fptr, sizeof fptr);
for(i=0;i<sizeof fptr;i++)
printf("%2X", pattern);
}

Another case might be if we are implementing the "prisoner's dilemma"
tournament. This is a competition in which one may either co-operate or
defect, mutual co-operation gives a bigger payoff than mutual defection, but
defecting when partner co-operates gives him nothing at all and you the
biggest payoff of all.

An obvious way to do it would be to encode strategies as C functions, then
have a big population of function pointers, which find partners at random.
As strategies succeed they get more copies in the pool - more function
pointers, that is.

In this program, though you are using function pointers, you are not passing
them to a subroutine so they are not "callback functions".
As far as the difference between virtual functions used in an
object oriented language and callback functions as they are
implemented in C, seems like the underlying mechanics can be
similar but that the term "callback" is really too low-level to be
used in an OOL.
Term "callback function" makes sense in terms of a program which is
basically a hard-coded tree of subroutines, but in which one or two function
pointers are passed dynamically.
In an OO design that makes heavy use of virtual functions the term stops
being useful since so many functions are called through pointers, so we use
the term "virtual member functions" instead. English usage is flexible so we
don't need to fuss too much if someone refers to these as "callback
functions".
 
P

Prashanth Ellina

Mike Wahler said:
#include <stdio.h>

struct S
{
int member;
void (*fp)(struct S *);
};

void func(struct S *param)
{
printf("%d\n", param->member);
}

int main()
{
struct S object = {42, func};
func(&object); /* prints 42 */


shouldn't the above line be,
object.fp(&object);
?
 
S

Stephen Sprunk

Chris Torek said:
There is still a lot of "wool" in this attempt to "define by example",
so let me try a more formal specification. This is just my attempt,
not any sort of "official" definition for a callback function:

A function is labeled "callback" when it is "called back" by
a separate body of code that is called to perform some specific
task. That is, code-group A calls code-group B, and code-group
B does most of the work, but occasionally needs processing by
code-group A. If that extra processing is supplied by having
code-group B call a specified function within code-group A,
the designated function in A is a "callback".

This is nearly identical to the loose definition I've been operating under.

One thing I'd add is that, while not required, code-group B was usually
written, translated, and installed long before code-group A was even
conceived. qsort() is obviously a perfect example from the standard
library, but in my experience GUI toolkits are the more common (and less
trivial) users of callback functions.

S
 
S

Stephen Sprunk

E. Robert Tisdale said:
Yes, a virtual function table may be implemented as a jump table.
But the function pointers in a jump table point to callback functions.

I said nothing about virtual functions, nor does Standard C define such.
Quit trying to confuse someone with a legitimate question.

The usage of jump tables I had in mind doesn't remotely resemble a callback
model, so obviously the former does not imply the latter.

S
 
E

E. Robert Tisdale

Stephen said:
The usage of jump tables [that] I had in mind
doesn't remotely resemble a callback model,

Do you mind sharing with us
the usage of jump tables that you *did* have in mind?
 
S

Stephen Sprunk

E. Robert Tisdale said:
Stephen said:
The usage of jump tables [that] I had in mind
doesn't remotely resemble a callback model,

Do you mind sharing with us
the usage of jump tables that you *did* have in mind?

Grossly simplified, this is how the core parsing in ircd works:

static void parse_foo(char *user, char *channel, char *command);
static void parse_bar(char *user, char *channel, char *command);
static void parse_baz(char *user, char *channel, char *command);
static void parse_zot(char *user, char *channel, char *command);

struct parser_record {
char *command;
void (*parser)(char *, char *, char *);
}

struct parser_record parser_table_user[] = {
{ "FOO", parse_foo },
{ "BAR", parse_bar },
{ "BAZ", parse_baz },
{ NULL, NULL}
}

struct parser_record parser_table_operator[] = {
{ "FOO", parse_foo },
{ "BAZ", parse_baz },
{ "ZOT", parse_zot },
{ NULL, NULL}
}

int parse_main(struct parser_record parsers[], char *user, char *channel,
char *command, char *arguments) {
int i;

for (i=0; parsers.command; i++)
if (!strcmp(parsers.command, command)) {
parsers.parser(user, channel, arguments);
return 0;
}

return -1;
}


I know there's probably typos in there, but that's the gist of it. Since
the command selector is a string, it can't be used in a switch statement,
and keeping the list of commands and their respective parsers in an array
also makes it very easy to add and remove commands without touching the core
logic. And, since the list of commands is stored outside said logic, it
also allows different users to get a different list of valid commands (or
the same commands pointing to different parsers) just by passing in a
different array to the same core logic.

S
 
E

E. Robert Tisdale

Stephen said:
E. Robert Tisdale said:
Stephen said:
The usage of jump tables [that] I had in mind
doesn't remotely resemble a callback model,

Do you mind sharing with us
the usage of jump tables that you *did* have in mind?

Grossly simplified, this is how the core parsing in ircd works:

static void parse_foo(char *user, char *channel, char *command);
static void parse_bar(char *user, char *channel, char *command);
static void parse_baz(char *user, char *channel, char *command);
static void parse_zot(char *user, char *channel, char *command);

These are the callback functions.
struct parser_record {
char *command;
void (*parser)(char *, char *, char *);
};

struct parser_record parser_table_user[] = {
{ "FOO", parse_foo },
{ "BAR", parse_bar },
{ "BAZ", parse_baz },
{ NULL, NULL}
};

struct parser_record parser_table_operator[] = {
{ "FOO", parse_foo },
{ "BAZ", parse_baz },
{ "ZOT", parse_zot },
{ NULL, NULL}
};

int parse_main(struct parser_record parsers[],
char *user, char *channel, char *command, char *arguments) {

for (int i = 0; parsers.command; ++i)
if (!strcmp(parsers.command, command)) { // callback
parsers.parser(user, channel, arguments);
return 0;
}

return -1;
}

I know [that] there's probably typos in there, but that's the gist of it.
Since the command selector is a string, it can't be used in a switch statement
and keeping the list of commands and their respective parsers in an array
also makes it very easy to add and remove commands
without touching the core logic.
And, since the list of commands is stored outside said logic,
it also allows different users to get a different list of valid commands
(or the same commands pointing to different parsers)
just by passing in a different array to the same core logic.


To me, that sounds like a typical description of callback functions.
 
A

Arthur J. O'Dwyer

Stephen said:
E. Robert Tisdale said:
Stephen Sprunk wrote:

The usage of jump tables [that] I had in mind
doesn't remotely resemble a callback model,

Do you mind sharing with us
the usage of jump tables that you *did* have in mind?

Grossly simplified, this is how the core parsing in ircd works:

static void parse_foo(char *user, char *channel, char *command);
static void parse_bar(char *user, char *channel, char *command);
static void parse_baz(char *user, char *channel, char *command);
static void parse_zot(char *user, char *channel, char *command);

These are the callback functions.

These are functions, but they are not callback functions. Not
every function is a callback function. Some programs do not use
callback functions at all. Stephen's program appears to be one of
them. Now please stop. At this point you are deliberately posting
misinformation, and that is wrong.

To Stephen and the rest: I think the record is fairly set
straight now; please no more feeding this troll.

-Arthur
 
E

E. Robert Tisdale

Arthur said:
These are functions, but they are not callback functions.

That's a lie.
Not every function is a callback function.
Some programs do not use callback functions at all.

I never said different.
Stephen's program appears to be one of them.

Stephen Sprunk's does, in fact, use callback functions.
It is a classical example of the use of callback functions.

You have never provided a single reason
why you believe that these are not callback functions.
I submit that the reason is that you can't
and that you know that you can't.
You are simply trolling.

Please go away troll.
 
C

CBFalconer

Chris said:
.... snip ...


You might find a good example in a state-machine, such as this
skeleton that works with a hardware device:

.... snip example ...

Another example is the initialization call to my hashlib system:

/* initialize and return a pointer to the data base */
hshtbl *hshinit(hshfn hash, hshfn rehash,
hshcmpfn cmp,
hshdupfn dupe, hshfreefn undupe,
int hdebug);

where the hash and rehash create hashvalues from a data item, cmp
compares them, dupe and undupe create and free storage for them.
These all operate on void* parameters, so only the caller to
hshinit needs to know their actual format.

Callback is, to me, a silly name. TTBOMK it never appears in the
C standard. However function pointers have many uses.
 
C

Christian Bau

"E. Robert Tisdale said:
Stephen said:
E. Robert Tisdale said:
Stephen Sprunk wrote:

The usage of jump tables [that] I had in mind
doesn't remotely resemble a callback model,

Do you mind sharing with us
the usage of jump tables that you *did* have in mind?

Grossly simplified, this is how the core parsing in ircd works:

static void parse_foo(char *user, char *channel, char *command);
static void parse_bar(char *user, char *channel, char *command);
static void parse_baz(char *user, char *channel, char *command);
static void parse_zot(char *user, char *channel, char *command);

These are the callback functions.

To me, that sounds like a typical description of callback functions.

Only to you.

Lets call them "Tisdale callback function".

Definition: A function pointer is by definition a "Tisdale callback
function".

Theorem 1: A "Tisdale callback function" is usually not a callback
function.
Proof: See post of Stephen Sprunk.

Theorem 2: Tisdale hasn't got a clue.
Proof: Only someone without a clue would proclaim that every "Tisdale
callback function" is a callback function. Tisdale does so. Therefore
Tisdale hasn't got a clue.
 
D

Default User

Arthur J. O'Dwyer said:
These are functions, but they are not callback functions. Not
every function is a callback function. Some programs do not use
callback functions at all. Stephen's program appears to be one of
them. Now please stop. At this point you are deliberately posting
misinformation, and that is wrong.

At this point? I think every post including the first one in this thread
were more of Trollsdale's deliberate and malicious campaign to misinform
and cause trouble.
To Stephen and the rest: I think the record is fairly set
straight now; please no more feeding this troll.


Indeed.




Brian Rodenborn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Pointer casts for OOP 2
C exercise 1
Meme generator in c 1
Copy string from 2D array to a 1D array in C 1
OOP 13
Filter sober in c++ don't pass test 0
[C#] Extend main interface on child level 0
Learning OOP 1

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top