I am new to the C language and pointers and I am confused by this function declaration:
void someFunction(int (*)(const void *, const void *));
Can anyone explain in layman's terms what this does and how it works?
It's the prototype of a function that takes:
a pointer to a function that takes a const void* and a const void* as arguments and returns an int
as an argument, and returns void.
It declares a function, which takes another function as its argument, and returns nothing. The other function would be declared as
int otherfunction( const void *, const void * );
and you would call somefunction() like this:
somefunction( otherfunction );
It's a function that has a single parameter. That parameter is a pointer to a function that returns an int and takes those two void pointers to constant data parameters.
This is the declaration of a function which takes a function pointer as its argument. In its most basic form, it looks like this:
void someFunction(argument_type);
Where argument_type is int (*)(const void *, const void *), which can be described as a "pointer to a function that takes two const void * arguments, and returns an int". i.e. any function that has the following declaration:
int foo(const void *, const void *);
To illustrate by example:
int foo_one(const void * x, const void * y) { ... }
int foo_two(const void * x, const void * y) { ... }
void someFunction(int (*)(const void *, const void *) function_ptr)
{
const void * x = NULL;
const void * y = NULL;
int result;
result = (*function_ptr)(x, y); // calls the function that was passed in
}
int main()
{
someFunction(foo_one);
someFunction(foo_two);
return 0;
}
Check this very helpful when dealing with complex declarations.
Related
my code: https://godbolt.org/z/de7fbdjh7
code from source: https://stackoverflow.com/a/49072888/15603477
Almost exact the same.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int iValue;
int kValue;
char label[6];
} my_data;
int cmp_mydata_ivalue(my_data* item1 , my_data* item2 )
{
if(item1->iValue < item2->iValue) return -1;
if(item1->iValue > item2->iValue) return 1;
return 0;
}
int main(void){
my_data datalist[256] = {0};
{
int i;
for(i = 0;i<20;i++){
datalist[i].iValue = i+100;
datalist[i].kValue = i+1000;
sprintf(datalist[i].label,"%2.2d", i+10);
}
}
printf("new line\n");
{
my_data srchitem = {105,1018,"13"};
my_data *foundItem = (my_data*) bsearch(&srchitem, datalist,20, sizeof(my_data),cmp_mydata_ivalue);
bsearch_results(&srchitem, foundItem);
}
}
The same question asked many times. But I don't know how to cast it.
error code:
*callback1.c: In function ‘main’:
callback1.c:58:89: warning: passing argument 5 of ‘bsearch’ from incompatible pointer type [-Wincompatible-pointer-types]
58 | my_data *foundItem = (my_data*) bsearch(&srchitem, datalist,20, sizeof(my_data),cmp_mydata_ivalue);
| ^~~~~~~~~~~~~~~~~
| |
| int (*)(my_data *, my_data *) {aka int (*)(struct <anonymous> *, struct <anonymous> *)}*
One way to try to use gcc option to supress the error. Another way is somewhere I need to cast. But now i don't know how to cast.
Tutorial I found so far: https://www.tutorialspoint.com/c_standard_library/c_function_bsearch.htm
The comparison function must have the type
int ( const void *, const void * )
See the declaration of the function bsearch
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
So you should declare and define your function like
int cmp_mydata_ivalue( const void *a , const void *b )
{
const my_data *item1 = a;
const my_data *item2 = b;
if ( item1->iValue < item2->iValue) return -1;
if(item1->iValue > item2->iValue) return 1;
return 0;
}
Don't ever use workarounds to suppress errors/warnings from the compiler. You should carefully understand them and fix the code instead. If you chose to ignore them, you must be very conscious of what are the implications.
Having said that, the bsearch prototype is the following:
void* bsearch( const void *key, const void *ptr, size_t count, size_t size,
int (*comp)(const void*, const void*) );
meaning it expects the last parameter to be a function pointer to a function with the following signature:
int function(const void*, const void*);
What you are passing is a function of this kind
int cmp_mydata_ivalue(my_data* item1 , my_data* item2 )
Which is uncompatible, as C can't do any implicit cast. You must rewrite your function to something like this:
int cmp_mydata_ivalue( const void *cvp_item1 , const void *cvp_item2 )
{
const my_data *item1 = (const my_data *)cvp_item1;
const my_data *item2 = (const my_data *)cvp_item2;
}
I have an error when I compile my C program.
I have this code :
#include <stdio.h>
#include <stdlib.h>
#define SET__SIZE 10
#define SET__BOUND ((void*) NULL)
struct set {
void *s[SET__SIZE];
int cursor;
int (*cmp)(const void*, const void*);
void * (*copy)(const void*);
void (*del)(void *);
};
int find(const void *s[], void *c, int (*cmp)(const void*, const void*))
{
int i = 0;
while (s[i]!=SET__BOUND && cmp(s[i],c)<0)
i++;
return i;
}
int set__find(const struct set *se, void *c)
{
return (se->cmp(se->s[find(se->s,c,se->cmp)],c)==0);
}
For some reason, gcc is raising a warning for the find call in set__find saying :
note: expected ‘const void **’ but argument is of type ‘void * const*’
I can't understand why he thinks the argument is a constant pointer (if I understood the error right)
As I tried, the note goes away, when I change the code to
struct set {
void *s[SET__SIZE];
int cursor;
int (*cmp)(const void*, const void*);
void * (*copy)(const void*);
void (*del)(void *);
};
int find(void * const s[], void *c, int (*cmp)(const void*, const void*))
{
int i = 0;
while (s[i]!=SET__BOUND && cmp(s[i],c)<0)
i++;
return i;
}
int set__find(const struct set *se, void *c)
{
return (se->cmp(se->s[find(se->s,c,se->cmp)],c)==0);
}
Explanation
In the answer... No point of writting it again.
why he thinks the argument is a constant pointer
struct set {
void *s[SET__SIZE];
The structure set contains the array s.
const struct set *se
se points to a constant structure set. Because the structure is constant, the memory for the structure is constant. The elements of the array s can't be modified, they are in constant memory.
find(se->s,
Arrays decay to the pointer to the first element. So imagine it's TYPE s[SET__SIZE] where TYPE is a void*. TYPE s[SET__SIZE] decays to a pointer TYPE *. But, it's constant, so it's const TYPE s[SET__SIZE]. So it decays to a const TYPE *. You can't modify it, it's a constant array. TYPE is a void* - you can dereference the element and modify it then, but you can't modify the pointer value itself.
TL;DR you want int find(void * const s[] as in the other answer.
I am not sure about this function pointer type declaration syntax, but it works. The syntax is just like declaring a regular old function.
typedef struct Element GetChildCallback(void *userdata, usize parent, usize child_no);
I couldn't find any information on how standard-compliant it is or what drawbacks it could possibly have.
I thought this only worked for typedefs, so I took a step further and found out this also works for regular function parameters:
extern inline void dmpstrn(const char *t, usize n, int printer(const char *fmt, ...));
inline void dmpstrn(const char *t, usize n, int printer(const char *fmt, ...)) {
usize len = strlen(t) > n ? n : strlen(t);
printer("\"");
for (usize i = 0; i < len; i += 1) {
if (t[i] == '\n')
printer("\\n");
else
printer("%c", t[i]);
}
printer("\"\n");
}
// ...
int main() {
dmpstrn("Hello\nworld", UINT64_MAX, printf);
}
This however doesn't work for variables
int printer(const char *fmt, ...) = printf; // Invalid
It's as if the it isn't the function pointer but the actual function, but what does it mean?
Function declarations used as function parameters are implicitly adjusted by the compiler to pointers to the function types.
From the C Standard (6.7.6.3 Function declarators (including prototypes))
8 A declaration of a parameter as ‘‘function returning type’’ shall be
adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1
So for example these two function declarations
void f( void( int ) );
and
void f( void ( * )( int ) );
declare the same one function.
On the other hand (6.3.2.1 Lvalues, arrays, and function designators)
4 A function designator is an expression that has function type.
Except when it is the operand of the sizeof operator65) or the unary &
operator, a function designator with type ‘‘function returning type’’
is converted to an expression that has type ‘‘pointer to function
returning type’’
Here is a demonstrative program.
#include <stdio.h>
typedef void F( int );
F display;
void g( F );
void g( F *f )
{
int x = 10;
f( x );
}
void display( int x )
{
printf( "x = %d\n", x );
}
int main(void)
{
F *fp = display;
g( fp );
return 0;
}
The program output is
x = 10
Investigate the program.
Pay attention to that for example this typedef
typedef void F( int );
may be equivalently rewritten like
void typedef F( int );
typedef struct Element GetChildCallback(void *userdata, usize parent, usize child_no);
This defines GetChildCallback as the actual "function type", which is different from the pointer to function type. This can be used to declare a function or form the pointer to function type, but not to define a function:
GetChildCallback MyButtonCB; /* OK, declares function */
GetChildCallback MyResizeCB {} /* ERROR, bad syntax */
struct Element MyButtonCB(void *, usize, usize) {} /* OK */
GetChildCallback cb1 = MyButtonCB; /* ERROR, bad function definition */
GetChildCallback* cb2 = MyButtonCB; /* OK */
void add_callback(Button* button, GetChildCallback* cb); /* OK */
When a function type is used as a function parameter, it silently becomes the pointer to function type, just like an array parameter type becomes the element pointer type. So your example
inline void dmpstrn(const char *t, usize n, int printer(const char *fmt, ...)) {
means just the same as
inline void dmpstrn(const char *t, usize n, int (*printer)(const char *fmt, ...)) {
including the fact that printer in the function body is a pointer to function, so for example (&printer) does not act the same as (printer).
For a class assignment we are writing a program which takes in input, and sorts each line of input with qsort with strcmp as its comparator function. Because the type of strcmp is not the same as required by qsort, a wrapper function needs to be built to satisfy qsort.
I wasn't satisfied with this, and wanted to write a function which takes in a function of type:
int (*cmp)(const char *, const char *)
and returns a function of type:
int (*qsortcmp)(const void *, const void *)
Is this possible? Have I been writing too much haskell? I would like to know.
C does not support lambda functions. Your only choice is to create a function of the type expected by qsort and call strcmp from inside of that function.
For example:
int qsort_cmp_str(const void *a, const void *b)
{
const char *s1 = a;
const char *s2 = b;
return strcmp(s1, s2);
}
It’s possible only with a global variable that holds the real function to call. (Yes, that’s horrible.)
There is a reason: a function pointer with only the obvious parameters cannot represent a closure. Had qsort accepted a pointer of type
int (*)(void *closure, const void*, const void*)
and a void* to pass it for each comparison, it would be possible to write a converter:
struct char_qsorter {
int (*function)(void*, const char*, const char*);
void *param;
};
struct qsorter {
int (*function)(void*, const void*, const void*);
void *param;
};
int char_qsort_wrapper(void *closure, const void *a, const void *b) {
const char_qsorter *const cq=closure;
return cq->function(cq->param, a, b);
}
qsorter convert(const char_qsorter *cq) {
const qsorter ret={char_qsort_wrapper, cq};
return ret;
}
/* Convert a plain function pointer: */
int trivial_wrapper(void *closure, const char *a, const char *b) {
return (*(int (*const *)(const char*, const char*))closure)(a, b);
}
char_qsorter trivial_closure(int (*const *f)(const char*, const char*)) {
const char_qsorter ret={trivial_wrapper, f};
return ret;
}
void sort_strings(const char *const *ss, size_t n) {
int (*const f0)(const char*, const char*)=strcmp;
const char_qsorter cq=trivial_closure(&f0);
const qsorter q=convert(&cq);
qsort_closure(ss, n, sizeof(*ss), q.function, q.param);
/* or just pass q if the library used the struct */
}
I think it’s obvious why in practice people prefer the hardcoded solution where it’s sufficient. (Really, lazy programmers just pass strcmp directly, which works on most implementations.)
C11 does support this with qsort_s, but it’s a special optional function with weird runtime error checking added on.
void dispatch_for(dispatch_queue_t *queue, long number, void (* work)(long)){
int loop = number;
int i;
task_t *ctask;
for(i = 0; i<loop;i++){
ctask = create_task((void *)work,number,"for_test");
dispatch_async(queue,ctask);
}
}
task_t *task_create(void (* work)(void *), void *param, char* name){
//do something
}
I'm getting work as a function and need to pass it to the function create_task..(1st parameter)
How should i pass it?
name of the function without the parentheses is the pointer to that function :
void work(void) {
...;
}
void main(void) {
task_create(work, void, void);
}
Just use the identifier like any other parameter:
dispatch_for(queue, number, work);
The easiest thing would be a typedef to the wanted function type. So you can do
typedef void workfunc_t(void *);
workfunc_t sample_workfunc; // in order to ensure type-correctness
void workfunc_t(void *)
{
// ...
}
void dispatch_for(dispatch_queue_t *queue, long number, workfunc_t * work)
{
int loop = number;
int i;
task_t *ctask;
for(i = 0; i<loop;i++) {
ctask = create_task(work, number, "for_test");
dispatch_async(queue,ctask);
}
}
task_t *task_create(workfunc_t work, void *param, char* name){
//do something
}
The function work doesn't have the same signature in dispatch_for and task_create (the argument is a pointer in one, a long in the other)
It seems strange you want to use the same function in both cases
Since you're using C, and work is a type void (*)(long), but you want to make it a void (*)(void*), simply re-cast the type of work (this is can be done the easiest by using a typedef)
//declare somewhere at a global level
typedef void (*task_create_func)(void*);
//at the point where you want to call task_create
task_create((task_create_func)work, PARAM1, PARM2);
Alternatively, if you don't want to deal with typedefs, you can simply do the cast using the desired pointer-type at the point-of-call like so:
task_create((void (*)(void*))work, PARAM1, PARAM2);