Related
I would like to send callbacks with different signatures for the same function. Somenthing like this:
#include <stdio.h>
#include <stdarg.h>
void a(int pa) {}
void b(int pb1, float pb2) {}
// exec implementation
int main() {
exec(a, 1);
exec(b, 1, 2.3);
}
I thought of using something like:
void exec(void (*func)(...), ...) {
int arg1;
float arg2;
va_list valist;
va_start(valist, size);
arg1 = va_arg(valist, int);
if (size == 1) {
(*func)(arg1);
va_end(valist);
return;
}
arg2 = va_arg(valist, float);
if (size == 2) {
(*func)(arg1, arg2);
va_end(valist);
return;
}
}
But obviously it doesn't work :(
The usual solution to making callback function interfaces flexible with respect to data provided to the function is to give the callback signature a void * parameter (possibly in addition to other parameters). Arbitrary data can be provided via such a parameter. Something like this:
void exec(void (*func)(void *), void *data) {
func(data);
}
struct s2 {
int i;
float f;
};
void func1(void *data) {
int i = *(int *)data;
// ...
}
void func2(void *data) {
struct s2 s = *(struct s2 *)data;
// ...
}
int main(void) {
int i = 42;
struct s2 s = { .i = 17, .f = 3.14 };
exec(func1, &i);
exec(func2, &s);
}
HOWEVER, It is possible to do something more like you describe, where the callback functions genuinely have different signatures, by specifying the callback type without a prototype. In that case, there are still at least these caveats:
If the callback functions themselves are defined with prototypes (as they should be) then the parameter types should not be any that are altered by the default argument promotions. So, pointers, ints, doubles, but not floats or short ints or chars (not an exhaustive list). If you wanted to support other parameter types then you would need to cast the function pointer before calling the function, as described later.
The callback functions cannot be variadic.
If the front-end is variadic, then it needs to be told at runtime, somehow, what the actual number and types of the arguments are.
Furthermore, there will need to be explicit calls to the callback functions, with correct arguments, so there can be only a fixed set of predetermined callback signatures supported.
For example, that might look something like this:
enum sig { INT, INT_DOUB };
void exec(void (*func)(/* no prototype */), enum sig cb_sig, ...);
void a(int pa) {}
void b(int pb1, double pb2) {}
int main(void) {
exec(a, INT, 1);
exec(b, INT_DOUB, 1, 2.3);
}
void exec(void (*func)(/* no prototype */), enum sig cb_sig, ...) {
va_list valist;
va_start(valist, cb_sig);
switch (cb_sig) {
case INT: {
int i = va_arg(valist, int);
func(i);
break;
}
case INT_DOUB: {
int i = va_arg(valist, int);
double d = va_arg(valist, double);
func(i, d);
break;
}
default:
assert(("Can't be reached", 0));
}
va_end(valist);
}
It is possible that that would elicit a few warnings, such as about a function declaration that does not provide a prototype, and about calling a (declared, but) unprototyped function. Since you know the signatures by the time you execute the calls, however, you could get rid of the latter kind of warning via appropriate casting. For example,
// ...
case INT: {
int i = va_arg(valist, int);
((void (*)(int))func)(i);
break;
}
// ...
You could change the callbacks to take a single va_list argument:
void a(va_list args)
{
int pa = va_arg(args,int);
}
void b(va_list args)
{
int pb1 = va_arg(args,int);
double pb2 = va_arg(args,double);
}
And have your other function pass the va_list along.
void exec(void (*func)(va_list), ...)
{
va_list valist;
va_start(valist, func);
func(valist);
va_end(valist);
}
You can use va_args to solve this.
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#define exec_func(func, ...) func(__VA_ARGS__)
long func(char *a, int b, long c, long d)
{
printf("a: %s, b: %d, c: %ld, d: %ld\n", a, b, c, d);
return c + d;
}
int main()
{
printf("c + d: %ld\n", exec_func(func, "test", 10, 1000, 1000));
}
I have a struct of pointers and a global pointer to use in functions declared after main. Now declaring the functions with those same name of pointers is fine. But when I call it within another function (because its like a menu type program), I kept getting different types of errors.. Like expression is needed, unexpected type, etc. My question is simply how to I call the parameters for the function to work. I haven't used C in years so the solution might seem simpler than it sounds like. The code below will show you what I mean.
StudentPtr studentArray
StudentPtr** studentArray
struct StudentPtr *studentArray
*StudentPtr studentArray[]
(Pretty much moving the pointers around and using struct as prefix)
typedef struct Student {
char *firstName;
char *lastName;
char *id;
char *email;
} Student, *StudentPtr;
//Prototypes:
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);
int displayData(StudentPtr studentArray, int n);
int displayDataAll(StudentPtr studentArray);
int main()
{
return 0;
}
int command(char line[])
{
//other code here
//some more code..
//......
//error below
if(lineSize==0) /* If the command is empty, asks again for a command */
{
return 0;
}
else
{
if(strncmp(line,"1",lineSize)==0)
{reset();}
else if(strncmp(line,"2",lineSize)==0)
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
else if (strncmp(line,"3",lineSize)==0)
{modify(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //here as well
else if(strncmp(line,"4",lineSize)==0)
{displayDataAll(StudentPtr studentArray);} //here too
else if(strncmp(line,"5",lineSize)==0)
{return 1;}
else
{noComm();}
}
return 0;
}
//example of the functions supposed to be used
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n)
{
//get the start of the nth record
//Ptr arithmetic
StudentPtr currentStudentptr = studentArray+(n-1);
//allocate memory for the character pointers
currentStudentptr->firstName =malloc(sizeof(char)*20);
strcpy(currentStudentptr->firstName,f);
//... same for others
return 0;
}
The calling of the function here should properly call the functions that are further down.
You are mixing syntax for function declaration and definition with syntax for calling a function:
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
In a function call you mustn't specify the type. You only provide the arguments:
{fillData(studentArray, f, l, id, e, n);}
You do not show any variable definiton. Therefore I cannot tell if the variables have correct types or if you need to add some & operators here and there...
That is the reason why a minimum complete verifyable example is mandatory.
Previously I asked How to make a function which receive a function as param in C language. I get an answer Link to the question but this solution is based on the parameters of argument's function. I mean:
int functionToPassAsParameter (int arg1, int arg2){
// do something
}
int functionWhichReceiveFunction (int (*f)(), int arg1, int arg2){
// do something
f(arg1, arg2);
// do something
}
// How to call the function
functionWhichReceiveFunction (&functionToPassAsParameter, 1, 2);
I would like something like:
int functionToPassAsParameter (int arg1, int arg2){
// do something
}
int functionWhichReceiveFunction ( f() ){
// do something
f();
// do something
}
// How to call the function
functionWhichReceiveFunction ( functionToPassAsParameter(arg1, arg2) );
So, when I call the function, I pass the correctly params but when I define the function which receive the other function I do not specify which params I will send to it. Is that possible to make?
EDIT 1:
I wanna achieve pass any function to functionWhichReceiveFunction. Something like:
int function_a (int param1, int param2) { /* Do something */ };
void function_b (char *arg1) { /* Do something */ };
// Call the function with two differents functions regardless return type nor params
int x = functionWhichReceiveFunction ( function_a(param1, param2) );
functionWhichReceiveFunction ( function_b(arg1) );
Define the function to be passed to take a void * as a parameter. That way the function that calls the given function doesn't need to know anything specific about the parameters:
struct params1 {
int arg1;
int arg2;
};
struct params2 {
char *arg1;
char *arg2;
};
int functionToPassAsParameter (void *param){
struct params1 *args = params;
// do something
}
int otherFunctionToPassAsParameter (void *param){
struct params2 *args = params;
// do something
}
int functionWhichReceiveFunction (int (*f)(void *), void *args) {
// do something
f(args);
// do something
}
struct params1 p1 = { 1, 2 };
functionWhichReceiveFunction (&functionToPassAsParameter, &p1);
struct params2 p2 = { "abc", "def" };
functionWhichReceiveFunction (&otherFunctionToPassAsParameter, &p2);
To be able to pass a function with unknown parameters to a function, declare the function that will pass the function as follows:
int g(int (*f)());
The function that is actually passed can have any number of parametes, for example:
int f(int x, void *y);
The call is now as follows:
g(f);
The above means that g passes f, which can have zero or more parameters of any type. This is denoted by the empty parameter list.
A particular function that may need to be passed is for example f.
Now g is called with function f, or any other function.
Note that it is up to g to know which parameters must be passed in calling f. So you need a "protocol" that tells g which function/type is passed. For example, besides passing the function, pass an identifier (int) that says what type of function is passed, for example:
#define fS_I_I 1 // f needs String, int, Int
#define fD_I 2 // f needs Double, Int
#define fI_I 3 // f needs Int, Int
int g(int ID, int (*f)());
g(fI_I, f);
Learn more about closures and tagged unions. Notice that C don't have them. You might want to emulate that with callbacks
I wanna achieve pass any function to functionWhichReceiveFunction
You cannot do that simply and portably. Remember that the signature of a function in C is related to its calling conventions (so to the ABI used by your compiler and your code; for examples, look into Linux x86 ABIs; so floating point arguments could be passed in different registers as integral arguments, so your compiler needs to know the signature of all your function pointers). You need to also give to functionWhichReceiveFunction something which describes the signature.
What you might consider doing, assuming your platform have function pointers of the same size and in the same address space as data pointers (this is very often the case), is to pass to functionWhichReceiveFunction a void* pointer (actually, a function pointer casted to void*) and an enumeration describing it.
For example
enum funsig_en {
funsig_void_to_void,
funsig_int_to_void,
funsig_int_to_double,
funsig_int_double_to_void,
};
Then, you'll have corresponding function signatures (types)
typedef void fun_void_to_void(void);
typedef void fun_int_to_void(int);
typedef double fun_int_to_double(int);
typedef void fun_int_double_to_void(int, double);
Suppose you have these static functions
static void statf_void_to_void(void);
static void statf_int_to_void(int);
static double statf_int_to_double(int);
static void statf_int_double_to_void(int, double);
You might declare
void
functionWhichReceiveFunction (void*res, enum funsig_en sigkind, void*fun, ...);
and you could use it as
functionWhichRecieveFunction(NULL, funsig_void_to_void
(void*)statf_void_to_void);
or
functionWhichRecieveFunction(NULL, funsig_int_to_void,
(void*)statf_int_to_void, 123);
or
double r = 0;
functionWhichRecieveFunction(&r, funsig_int_to_double,
(void*)statf_int_to_double, 2345);
I leave you to code that variadic functionWhichRecieveFunction. You need stdarg(3) facilities. It would include code like
va_args arglist;
va_start (arglist, fun);
switch(sigkind) {
case funsig_int_to_void: {
int a = va_arg(arglis, int);
fun_int_to_void* fptr = (fun_int_to_void*)fun;
(*fptr)(a);
return;
} // end case funsig_int_to_void
much later you'll need some va_end(arglis); near the end of your functionWhichRecieveFunction body.
Another possibility is using varargs. In the following example every function being called does its own interpretation of parameters.
#include <stdio.h>
#include <stdarg.h>
// expects 4 arguments (int, int, int, char*)
void f1(va_list args) {
int a, b, c;
char *d;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, int);
d = va_arg(args, char *);
printf("%d, %d, %d: %s\n", a, b, c, d);
}
// expects 3 ars (int, int, char*);
void f2(va_list args) {
int a, b;
char *c;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, char *);
printf("%d, %d: %s\n", a, b, c);
}
void caller(void (*f)(va_list), ...) {
va_list args;
va_start(args, f);
f(args);
va_end(args);
}
int main() {
caller(&f1, 0, 1, 3, "hello");
caller(&f2, 1, 2, "bye");
return 0;
}
Another possibility is to have caller to interpret parameters based on some type info and call a correct function call. This might be useful if you have a limited number of argument patterns and just regular functions to call:
void f3(int a, int b, int c, char *d) {
printf("%d, %d, %d: %s\n", a, b, c, d);
}
void f4(int a, int b, char *c) {
printf("%d, %d: %s\n", a, b, c);
}
typedef enum {
type1, type2
} Types;
void caller1(Types t, void (*f)(), ...) {
va_list args;
va_start(args, f);
switch (t) {
case type1: {
int a, b, c;
char *d;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, int);
d = va_arg(args, char *);
f(a,b,c,d);
break;
}
case type2: {
int a, b;
char *c;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, char *);
f(a,b,c);
}
}
va_end(args);
}
int main() {
caller1(type1, &f3, 3,2,1, "hi");
caller1(type2, &f4, 3,2,"take care");
return 0;
#Paul Ogilvie, this is the code:
int f(int x, void *y) {
return x;
};
int g(int (*f)()) {
int x = f(1, NULL); // call f with parameters
printf("X is: %d", x);
return(x); // return result
};
int main()
{
//g( f(1, 2) ); // this passes the result of a call to f, not f
g( f ); // this passes f
return 0;
}
I have this function:
void print(THashEntry *entry, ...)
{
va_list parameters;
va_start(parameters, entry);
while (true)
{
THashEntry *currentEntry = va_arg(parameters, THashEntry *);
if (!currentEntry)
{
break;
}
printf("%s\n", currentEntry->value);
}
va_end(parameters);
}
I pass adresses of these entries into the function and then I want to access their member "value" and print it.
However when I try to obtain a parameter via va_arg, it returns me not the first, but the second parameter right from the start and when another loop of cycle goes in, it's segmentation fault.
As John Kugelman states in his answer, here are some of the good practices to pass variable number of arguments to printf/sprintf:-
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
I apologize for butting into your design but this might be an alternative to use
struct abc {
int a;
char b[10];
};
void f(int size, abc* a) {
for (int i = 0; i < size; i++) {
abc x = a[i];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
abc *arrAbc = new abc[10];
for (int i = 0; i < 10; i++) {
arrAbc[i].a = 0;
}
f(10, arrAbc);
}
va_arg won't return NULL when you reach the end of argument list. As man va_arg says:
random erros will occur
So to get around it you either need to pass number of arguments to your print function, or end terminator.
To automatically calculate number of arguments at compile time, you can use macro
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
See more details in this answer
Seems like there are quite a few answers, but personally I've never found a great way to get around dynamically counting the number of args in a va_list.
That said, there are several ways around it:
Use the NUMARGS(...) macro as noted by qrdl
Pass the number of args into the function like as main does void print(int numArgs, MyEntry *entry, ...)
Use a NULL terminated list
The latter happens to be my personal preference, since it tends to go with my (and it looks like yours too) instinct to how to catch the end of the list. See below:
#import <stdarg.h>
typedef struct MyEntry {
int a;
int b;
} MyEntry;
void print(int numArgs, MyEntry *entry, ...) {
va_list parameters;
va_start(parameters, entry);
MyEntry *m;
for ( m = entry; m != NULL; m = va_arg(parameters, MyEntry *)) {
printf("%d\n", (int)m->a);
}
va_end(parameters);
}
int main(int argc, char *argv[]) {
MyEntry entry = { 10, 20 };
MyEntry entry2 = { 30, 40 };
MyEntry entry3 = { 50, 60 };
MyEntry entry4 = { 70, 80 };
MyEntry entry5 = { 90, 100 };
print(2, &entry, &entry2, &entry3, &entry4, &entry5, NULL);
return 1;
}
Happy coding!
What does this mean?
void message(int x, int y, ...)
I can't understand what ... is.
Can anybody explain?
... denotes a variable list of arguments that can be accessed through va_arg, va_end and va_start.
Unspecified/variable number of parameters. To handle such function you have to use the va_list type and va_start, va_arg, and va_end functions:
An example taken from here:
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT SUCCESS);
}
int maxof(int n args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
You can find more details here
You have defined a function message somewhere that takes at least two arguments of type int and then some optional arguments indicated by the "...". (printf is another function taking optional arguments).
The optional arguments can be accessed using the va_* functions.
... represents final argument passed as an array or as a sequence of arguments.
It's the variable argument formal parameter. From the syntactical prospective it allows you pass a variable number of parameters (at least two, which are x and y, but even more).