In C is there a way to set a function argument using function pointers such that all calls to that function pointer just use the set parameter? As an example, is it possible to do something like the code below?
void do_something(int *a, int *b, int *c){
*a = *c - 5;
*b = *c - 10;
}
typedef void (*funcptr)(int *a, int *b, int *c);
int main(){
int num = 5;
funcptr f = do_something(c=&num); // c = 5 for all calls to f(a, b)
int *a; int *b;
f(a, b); //a = 0, b = -5
num = 10;
f = do_something(c=&num); // c = 10 for all calls to f(a, b)
f(a, b); //a = 5, b = 0
}
This seems possible with external C libraries like Blocks and FFCALL, but it appears I'd need to set a, b, and c instead of setting a single argument.
no, this is not a language feature of C or of the C calling convention.
You'll need to construct function that calls your function pointer with that argument yourself; external libraries that provide such functionality are available, as you've noticed.
Another way, though I'm personally not overly fond of that is using <stdarg> and varargs, letting your function do one thing or another, depending on the number of arguments passed.
In C frameworks, you'll often find a lot of functions that work in some kind of context. That is often even used in implementation of object-oriented programming. I don't know the larger picture of what you want to implement, but often questions like these are rised in a context where someone wants to do something that resembles function overloading in C++; if that's the case, you might really just make functions that take a "state/context" argument, and further arguments, which might or might not be relevant, depending on the state.
Rather than using function pointers, you would need a wrapper function that uses a global for state.
void do_something(int *a, int *b, int c){
*a = c - 5;
*b = c - 10;
}
static int c_val = NULL;
void do_something_wrap(int *a, int *b)
{
do_something(a, b, c);
}
int main(){
int num = 5;
c_val = num;
int a; int b;
do_something_wrap(&a, &b); //a = 0, b = -5
num = 10;
c_val = num;
do_something_wrap(&a, &b); //a = 5, b = 0
}
C has no such features like default arguments or function overloading.
Moreover in this declaration
funcptr f = do_something;
the initializer shall be a function pointer.
Standard C has no such facility. Compilers offer extensions that allow this though. Nested functions in GCC, Blocks in clang or via a library like CALLBACK in clisp or assembling your call via libffi.
[..] is there a way [..] ?
There always is a way. The question is if it's worth the effort and possible downsides.
The following is based on another answer I gave about deferred (that is, called e.g. at the end of scope) function execution.
Start off with a unified type for a "partially applied function":
struct partially_applied {
void * data; // parameters
void (*function)(void *); // function unpacking parameters and calling actual function
void (*store)(void *, char const *, void *); // storing parameters
};
typedef struct partially_applied * FUN;
To make a function partially apply-able we need
a struct holding the (eventually) already applied parameters (I added an init function and an allocation function)
a function to unpack these and call the actual function
a function to store ("partially apply") parameters
Here we go:
#define MAKE_PARTIAL(fn, N, ...) \
struct partially_applied_ ## fn ## _data { \
DATA_DEF(N, __VA_ARGS__) \
}; \
\
static void init_partially_applied_ ## fn ## _data (void * p) { \
struct partially_applied_ ## fn ## _data * data = p; \
DATA_INIT(N, __VA_ARGS__); \
} \
\
static void * allocate_partially_applied_ ## fn ## _data (void) { \
void * data = malloc(sizeof(struct partially_applied_ ## fn ## _data)); \
if (data == NULL) { \
fprintf(stderr, "Allocation failure for " #fn " data\n"); \
exit(1); \
} \
init_partially_applied_ ## fn ## _data(data); \
return data; \
} \
\
static void partially_applied_ ## fn (void * p) { \
struct partially_applied_ ## fn ## _data * data = p; \
if (DATA_CHECK(N, __VA_ARGS__)) { \
fn(DATA_ACCESS(N, __VA_ARGS__)); \
} else { \
fprintf(stderr, "Not all parameters for " #fn " are vaild\n"); \
} \
} \
\
static void partially_applied_ ## fn ## _store ( \
void * p, char const * id, void * src) { \
struct partially_applied_ ## fn ## _data * data = p; \
DATA_STORE_CODE(N, __VA_ARGS__) \
fprintf(stderr, "Cannot store %s in " #fn "!\n", id); \
}
The above contains some macros. These depend on the number of macro arguments (which could be counted by the preprocessor, but I want to keep it simpler). To expand the correct macro (depending on the number of arguments) we need a little helper:
#define SPLICE_2(l,r) l##r
#define SPLICE_1(l,r) SPLICE_2(l,r)
#define SPLICE(l,r) SPLICE_1(l,r)
Now on to the macros. DATA_DEF defines the structure contents:
#define DATA_DEF_0(...)
#define DATA_DEF_1(type, name) type name; bool name ## _valid;
#define DATA_DEF_2(type, name, ...) type name; bool name ## _valid; DATA_DEF_1(__VA_ARGS__)
#define DATA_DEF_3(type, name, ...) type name; bool name ## _valid; DATA_DEF_2(__VA_ARGS__)
#define DATA_DEF_4(type, name, ...) type name; bool name ## _valid; DATA_DEF_3(__VA_ARGS__)
// add more to support more parameters
#define DATA_DEF(N, ...) SPLICE(DATA_DEF_,N)(__VA_ARGS__)
DATA_INIT expands to code to initialize such a structure:
#define DATA_INIT_0(...)
#define DATA_INIT_1(t, name) data->name ## _valid = false;
#define DATA_INIT_2(t, name, ...) data->name ## _valid = false; DATA_INIT_1(__VA_ARGS__)
#define DATA_INIT_3(t, name, ...) data->name ## _valid = false; DATA_INIT_2(__VA_ARGS__)
#define DATA_INIT_4(t, name, ...) data->name ## _valid = false; DATA_INIT_3(__VA_ARGS__)
// add more to support more parameters
#define DATA_INIT(N, ...) SPLICE(DATA_INIT_,N)(__VA_ARGS__)
DATA_CHECK expands to a condition testing if all arguments have been applied:
#define DATA_CHECK_0(...) true
#define DATA_CHECK_1(t, name) data->name ## _valid
#define DATA_CHECK_2(t, name, ...) data->name ## _valid && DATA_CHECK_1(__VA_ARGS__)
#define DATA_CHECK_3(t, name, ...) data->name ## _valid && DATA_CHECK_2(__VA_ARGS__)
#define DATA_CHECK_4(t, name, ...) data->name ## _valid && DATA_CHECK_3(__VA_ARGS__)
// add more to support more parameters
#define DATA_CHECK(N, ...) SPLICE(DATA_CHECK_,N)(__VA_ARGS__)
DATA_ACCESS expands into code for passing the parameters to the actual function (actually it's only the comma separated arguments list):
#define DATA_ACCESS_0(...)
#define DATA_ACCESS_1(t, name) data->name
#define DATA_ACCESS_2(t, name, ...) data->name, DATA_ACCESS_1(__VA_ARGS__)
#define DATA_ACCESS_3(t, name, ...) data->name, DATA_ACCESS_2(__VA_ARGS__)
#define DATA_ACCESS_4(t, name, ...) data->name, DATA_ACCESS_3(__VA_ARGS__)
// add more to support more parameters
#define DATA_ACCESS(N, ...) SPLICE(DATA_ACCESS_,N)(__VA_ARGS__)
And finally DATA_STORE_CODE expands into code to store the parameters:
#define DATA_STORE_CODE_OP(type, name) \
if (strcmp(id, #name) == 0) { data->name = *((type *) src); data->name ## _valid = true; return; }
#define DATA_STORE_CODE_0(...)
#define DATA_STORE_CODE_1(type, name) DATA_STORE_CODE_OP(type, name)
#define DATA_STORE_CODE_2(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_1(__VA_ARGS__)
#define DATA_STORE_CODE_3(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_2(__VA_ARGS__)
#define DATA_STORE_CODE_4(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_3(__VA_ARGS__)
// more
#define DATA_STORE_CODE(N, ...) SPLICE(DATA_STORE_CODE_,N)(__VA_ARGS__)
Adding little helpers to allocate and free partially applied function structures (data is expected to be allocated by malloc here) ...
FUN make_fun(void (*function)(void *), void (*store)(void *, char const *, void *), void * data) {
FUN f = malloc(sizeof(*f));
if (f == NULL) {
fprintf(stderr, "Allocation of FUN failed\n");
exit(1);
}
f->function = function;
f->store = store;
f->data = data;
return f;
}
void free_fun(FUN f) {
free(f->data);
free(f);
}
... we can go on to define a macro that actually makes an instance of a partially applied function:
#define PARTIAL(fn) make_fun(&(partially_applied_ ## fn), \
&(partially_applied_ ## fn ## _store), \
allocate_partially_applied_ ## fn ## _data())
Of course we want to be able to apply some arguments:
#define APPLY(PFN, N, ...) \
do { \
struct partially_applied * pfn = (PFN); \
DATA_STORE(N, __VA_ARGS__) \
} while(0)
The macro DATA_STORE expands into code to call the store functions multiple times, so that we can apply multiple arguments at once:
#define DATA_STORE_OP(name, value) pfn->store(pfn->data, #name, &(value));
#define DATA_STORE_0(...)
#define DATA_STORE_1(name, value) DATA_STORE_OP(name, value)
#define DATA_STORE_2(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_1(__VA_ARGS__)
#define DATA_STORE_3(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_2(__VA_ARGS__)
#define DATA_STORE_4(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_3(__VA_ARGS__)
#define DATA_STORE(N, ...) SPLICE(DATA_STORE_,N)(__VA_ARGS__)
Last but not least we want to be able to call such a function (this could also be a function, but well):
#define CALL(fn) (fn)->function((fn)->data)
Finally, an example:
void foo(char * str, int i) {
printf("FOO| str = %s, i = %d\n", str, i);
}
void bar(float f, int i, size_t s) {
printf("BAR| f = %f, i = %d, s = %zu\n", f, i, s);
}
MAKE_PARTIAL(foo, 2, char *, string, int, integer)
MAKE_PARTIAL(bar, 3, float, floating, int, INT, size_t, SOME_SIZE)
int main() {
FUN f = PARTIAL(foo);
char * c = "Crazy";
APPLY(f, 1, string, c);
printf("doing other stuff\n");
FUN g = PARTIAL(bar);
size_t size = 99;
APPLY(g, 1, SOME_SIZE, size);
int answer = 42;
APPLY(f, 1, integer, answer);
answer = 21;
float pi = 3.14;
APPLY(g, 2, INT, answer, floating, pi);
CALL(f);
printf("done\n");
CALL(g);
printf("now completely done\n");
return 0;
}
Some downsides:
macros. macros everywhere.
Losing some type safety (in APPLY)
Need for lvalues (APPLY(f, 1, integer, 42) does not work)
Related
If I have a function that produces a result int and a result string, how do I return them both from a function?
As far as I can tell I can only return one thing, as determined by the type preceding the function name.
I don't know what your string is, but I'm going to assume that it manages its own memory.
You have two solutions:
1: Return a struct which contains all the types you need.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Use pointers to pass out values.
void getPair(int* a, string* b) {
// Check that these are not pointing to NULL
assert(a);
assert(b);
*a = 1;
*b = getString();
}
void foo() {
int a, b;
getPair(&a, &b);
}
Which one you choose to use depends largely on personal preference as to whatever semantics you like more.
Option 1: Declare a struct with an int and string and return a struct variable.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2: You can pass one of the two via pointer and make changes to the actual parameter through the pointer and return the other as usual:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
or
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3: Similar to the option 2. You can pass both via pointer and return nothing from the function:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
Since one of your result types is a string (and you're using C, not C++), I recommend passing pointers as output parameters. Use:
void foo(int *a, char *s, int size);
and call it like this:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
In general, prefer to do the allocation in the calling function, not inside the function itself, so that you can be as open as possible for different allocation strategies.
Create a struct and set two values inside and return the struct variable.
struct result {
int a;
char *string;
}
You have to allocate space for the char * in your program.
Two different approaches:
Pass in your return values by pointer, and modify them inside the function. You declare your function as void, but it's returning via the values passed in as pointers.
Define a struct that aggregates your return values.
I think that #1 is a little more obvious about what's going on, although it can get tedious if you have too many return values. In that case, option #2 works fairly well, although there's some mental overhead involved in making specialized structs for this purpose.
One approach is to use macros. Place this in a header file multitype.h
#include <stdlib.h>
/* ============================= HELPER MACROS ============================= */
/* __typeof__(V) abbreviation */
#define TOF(V) __typeof__(V)
/* Expand variables list to list of typeof and variable names */
#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1;
#define TO0(_0) TOF(_0) v0;
#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO
#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)
/* Assign to multitype */
#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0) _0 = mtr.v0;
#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO
#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)
/* Return multitype if multiple arguments, return normally if only one */
#define MTR1(...) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t *mtr = malloc(sizeof(mtr_t)); \
*mtr = (mtr_t){__VA_ARGS__}; \
return mtr; \
}
#define MTR0(_0) return(_0)
#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO
/* ============================== API MACROS =============================== */
/* Declare return type before function */
typedef void* multitype;
#define multitype(...) multitype
/* Assign return values to variables */
#define let(...) \
for(int mti = 0; !mti;) \
for(multitype mt; mti < 2; mti++) \
if(mti) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t mtr = *(mtr_t*)mt; \
MTA(__VA_ARGS__) \
free(mt); \
} else \
mt
/* Return */
#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
This makes it possible to return up to four variables from a function and assign them to up to four variables. As an example, you can use them like this:
multitype (int,float,double) fun() {
int a = 55;
float b = 3.9;
double c = 24.15;
RETURN (a,b,c);
}
int main(int argc, char *argv[]) {
int x;
float y;
double z;
let (x,y,z) = fun();
printf("(%d, %f, %g\n)", x, y, z);
return 0;
}
This is what it prints:
(55, 3.9, 24.15)
The solution may not be as portable because it requires C99 or later for variadic macros and for-statement variable declarations. But I think it was interesting enough to post here. Another issue is that the compiler will not warn you if you assign them the wrong values, so you have to be careful.
Additional examples, and a stack-based version of the code using unions, are available at my github repository.
Use pointers as your function parameters.
Then use them to return multiple value.
By passing parameters by reference to function.
Examples:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Also by using global variables but it is not recommended.
Example:
int a=0;
void main(void)
{
//Anything you want to code.
}
If I have a function that produces a result int and a result string, how do I return them both from a function?
As far as I can tell I can only return one thing, as determined by the type preceding the function name.
I don't know what your string is, but I'm going to assume that it manages its own memory.
You have two solutions:
1: Return a struct which contains all the types you need.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Use pointers to pass out values.
void getPair(int* a, string* b) {
// Check that these are not pointing to NULL
assert(a);
assert(b);
*a = 1;
*b = getString();
}
void foo() {
int a, b;
getPair(&a, &b);
}
Which one you choose to use depends largely on personal preference as to whatever semantics you like more.
Option 1: Declare a struct with an int and string and return a struct variable.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2: You can pass one of the two via pointer and make changes to the actual parameter through the pointer and return the other as usual:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
or
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3: Similar to the option 2. You can pass both via pointer and return nothing from the function:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
Since one of your result types is a string (and you're using C, not C++), I recommend passing pointers as output parameters. Use:
void foo(int *a, char *s, int size);
and call it like this:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
In general, prefer to do the allocation in the calling function, not inside the function itself, so that you can be as open as possible for different allocation strategies.
Create a struct and set two values inside and return the struct variable.
struct result {
int a;
char *string;
}
You have to allocate space for the char * in your program.
Two different approaches:
Pass in your return values by pointer, and modify them inside the function. You declare your function as void, but it's returning via the values passed in as pointers.
Define a struct that aggregates your return values.
I think that #1 is a little more obvious about what's going on, although it can get tedious if you have too many return values. In that case, option #2 works fairly well, although there's some mental overhead involved in making specialized structs for this purpose.
One approach is to use macros. Place this in a header file multitype.h
#include <stdlib.h>
/* ============================= HELPER MACROS ============================= */
/* __typeof__(V) abbreviation */
#define TOF(V) __typeof__(V)
/* Expand variables list to list of typeof and variable names */
#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1;
#define TO0(_0) TOF(_0) v0;
#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO
#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)
/* Assign to multitype */
#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0) _0 = mtr.v0;
#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO
#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)
/* Return multitype if multiple arguments, return normally if only one */
#define MTR1(...) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t *mtr = malloc(sizeof(mtr_t)); \
*mtr = (mtr_t){__VA_ARGS__}; \
return mtr; \
}
#define MTR0(_0) return(_0)
#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO
/* ============================== API MACROS =============================== */
/* Declare return type before function */
typedef void* multitype;
#define multitype(...) multitype
/* Assign return values to variables */
#define let(...) \
for(int mti = 0; !mti;) \
for(multitype mt; mti < 2; mti++) \
if(mti) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t mtr = *(mtr_t*)mt; \
MTA(__VA_ARGS__) \
free(mt); \
} else \
mt
/* Return */
#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
This makes it possible to return up to four variables from a function and assign them to up to four variables. As an example, you can use them like this:
multitype (int,float,double) fun() {
int a = 55;
float b = 3.9;
double c = 24.15;
RETURN (a,b,c);
}
int main(int argc, char *argv[]) {
int x;
float y;
double z;
let (x,y,z) = fun();
printf("(%d, %f, %g\n)", x, y, z);
return 0;
}
This is what it prints:
(55, 3.9, 24.15)
The solution may not be as portable because it requires C99 or later for variadic macros and for-statement variable declarations. But I think it was interesting enough to post here. Another issue is that the compiler will not warn you if you assign them the wrong values, so you have to be careful.
Additional examples, and a stack-based version of the code using unions, are available at my github repository.
Use pointers as your function parameters.
Then use them to return multiple value.
By passing parameters by reference to function.
Examples:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Also by using global variables but it is not recommended.
Example:
int a=0;
void main(void)
{
//Anything you want to code.
}
If I have a function that produces a result int and a result string, how do I return them both from a function?
As far as I can tell I can only return one thing, as determined by the type preceding the function name.
I don't know what your string is, but I'm going to assume that it manages its own memory.
You have two solutions:
1: Return a struct which contains all the types you need.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Use pointers to pass out values.
void getPair(int* a, string* b) {
// Check that these are not pointing to NULL
assert(a);
assert(b);
*a = 1;
*b = getString();
}
void foo() {
int a, b;
getPair(&a, &b);
}
Which one you choose to use depends largely on personal preference as to whatever semantics you like more.
Option 1: Declare a struct with an int and string and return a struct variable.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2: You can pass one of the two via pointer and make changes to the actual parameter through the pointer and return the other as usual:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
or
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3: Similar to the option 2. You can pass both via pointer and return nothing from the function:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
Since one of your result types is a string (and you're using C, not C++), I recommend passing pointers as output parameters. Use:
void foo(int *a, char *s, int size);
and call it like this:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
In general, prefer to do the allocation in the calling function, not inside the function itself, so that you can be as open as possible for different allocation strategies.
Create a struct and set two values inside and return the struct variable.
struct result {
int a;
char *string;
}
You have to allocate space for the char * in your program.
Two different approaches:
Pass in your return values by pointer, and modify them inside the function. You declare your function as void, but it's returning via the values passed in as pointers.
Define a struct that aggregates your return values.
I think that #1 is a little more obvious about what's going on, although it can get tedious if you have too many return values. In that case, option #2 works fairly well, although there's some mental overhead involved in making specialized structs for this purpose.
One approach is to use macros. Place this in a header file multitype.h
#include <stdlib.h>
/* ============================= HELPER MACROS ============================= */
/* __typeof__(V) abbreviation */
#define TOF(V) __typeof__(V)
/* Expand variables list to list of typeof and variable names */
#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1;
#define TO0(_0) TOF(_0) v0;
#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO
#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)
/* Assign to multitype */
#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0) _0 = mtr.v0;
#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO
#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)
/* Return multitype if multiple arguments, return normally if only one */
#define MTR1(...) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t *mtr = malloc(sizeof(mtr_t)); \
*mtr = (mtr_t){__VA_ARGS__}; \
return mtr; \
}
#define MTR0(_0) return(_0)
#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO
/* ============================== API MACROS =============================== */
/* Declare return type before function */
typedef void* multitype;
#define multitype(...) multitype
/* Assign return values to variables */
#define let(...) \
for(int mti = 0; !mti;) \
for(multitype mt; mti < 2; mti++) \
if(mti) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t mtr = *(mtr_t*)mt; \
MTA(__VA_ARGS__) \
free(mt); \
} else \
mt
/* Return */
#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
This makes it possible to return up to four variables from a function and assign them to up to four variables. As an example, you can use them like this:
multitype (int,float,double) fun() {
int a = 55;
float b = 3.9;
double c = 24.15;
RETURN (a,b,c);
}
int main(int argc, char *argv[]) {
int x;
float y;
double z;
let (x,y,z) = fun();
printf("(%d, %f, %g\n)", x, y, z);
return 0;
}
This is what it prints:
(55, 3.9, 24.15)
The solution may not be as portable because it requires C99 or later for variadic macros and for-statement variable declarations. But I think it was interesting enough to post here. Another issue is that the compiler will not warn you if you assign them the wrong values, so you have to be careful.
Additional examples, and a stack-based version of the code using unions, are available at my github repository.
Use pointers as your function parameters.
Then use them to return multiple value.
By passing parameters by reference to function.
Examples:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Also by using global variables but it is not recommended.
Example:
int a=0;
void main(void)
{
//Anything you want to code.
}
I am trying to define a function using macros that would actually wrap an existing function into an other one with a prefix.
Let's say for example:
int f1(int a, void *b, char c) { return 1; }
int f2(void *a) { return 1; }
void f3(void *a, int b) {}
void f4() {}
#define WRAP(prefix, f) // do something
WRAP(a, f1) or WRAP(a,f1,int,void*,char) or WRAP(a,f1,int,a,void*,b,char,c)
This should produce something like:
int a_f1(int a, void *b, char c);
int a_f1(int a, void *b, char c) { return f1(a,b,c); }
I'm trying to do it so it could work with any of f1, f2, f3 or f4.
If anyone has an idea on how to do that I would be really thanksfull.
If you can be bothered to specify the return type and parameters of the wrapped function, Boost.Preprocessor has you covered:
#include <boost/preprocessor/tuple/to_seq.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/comma_if.hpp>
#define WRAP_declare_param(r, data, i, paramType) \
BOOST_PP_COMMA_IF(i) paramType _ ## i
#define WRAP_forward_param(r, data, i, paramType) \
BOOST_PP_COMMA_IF(i) _ ## i
#define WRAP_seq(prefix, retType, function, argSeq) \
inline retType prefix ## function ( \
BOOST_PP_SEQ_FOR_EACH_I(WRAP_declare_param, ~, argSeq) \
) { \
return function( \
BOOST_PP_SEQ_FOR_EACH_I(WRAP_forward_param, ~, argSeq) \
); \
}
#define WRAP(prefix, retType, function, ...) \
WRAP_seq(prefix, retType, function, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__)))
Which lets you write the following:
// Declared somewhere...
int foo(float, double);
WRAP(p_, int, foo, float, double)
// ^^ Prefix
// ^^^ Return type
// ^^^ Function
// ^^^^^^^^^^^^^ Parameter types
Which expands to:
inline int p_foo ( float _0 , double _1 ) { return foo( _0 , _1 ); }
If I have a function that produces a result int and a result string, how do I return them both from a function?
As far as I can tell I can only return one thing, as determined by the type preceding the function name.
I don't know what your string is, but I'm going to assume that it manages its own memory.
You have two solutions:
1: Return a struct which contains all the types you need.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Use pointers to pass out values.
void getPair(int* a, string* b) {
// Check that these are not pointing to NULL
assert(a);
assert(b);
*a = 1;
*b = getString();
}
void foo() {
int a, b;
getPair(&a, &b);
}
Which one you choose to use depends largely on personal preference as to whatever semantics you like more.
Option 1: Declare a struct with an int and string and return a struct variable.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2: You can pass one of the two via pointer and make changes to the actual parameter through the pointer and return the other as usual:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
or
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3: Similar to the option 2. You can pass both via pointer and return nothing from the function:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
Since one of your result types is a string (and you're using C, not C++), I recommend passing pointers as output parameters. Use:
void foo(int *a, char *s, int size);
and call it like this:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
In general, prefer to do the allocation in the calling function, not inside the function itself, so that you can be as open as possible for different allocation strategies.
Create a struct and set two values inside and return the struct variable.
struct result {
int a;
char *string;
}
You have to allocate space for the char * in your program.
Two different approaches:
Pass in your return values by pointer, and modify them inside the function. You declare your function as void, but it's returning via the values passed in as pointers.
Define a struct that aggregates your return values.
I think that #1 is a little more obvious about what's going on, although it can get tedious if you have too many return values. In that case, option #2 works fairly well, although there's some mental overhead involved in making specialized structs for this purpose.
One approach is to use macros. Place this in a header file multitype.h
#include <stdlib.h>
/* ============================= HELPER MACROS ============================= */
/* __typeof__(V) abbreviation */
#define TOF(V) __typeof__(V)
/* Expand variables list to list of typeof and variable names */
#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1;
#define TO0(_0) TOF(_0) v0;
#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO
#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)
/* Assign to multitype */
#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0) _0 = mtr.v0;
#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO
#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)
/* Return multitype if multiple arguments, return normally if only one */
#define MTR1(...) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t *mtr = malloc(sizeof(mtr_t)); \
*mtr = (mtr_t){__VA_ARGS__}; \
return mtr; \
}
#define MTR0(_0) return(_0)
#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO
/* ============================== API MACROS =============================== */
/* Declare return type before function */
typedef void* multitype;
#define multitype(...) multitype
/* Assign return values to variables */
#define let(...) \
for(int mti = 0; !mti;) \
for(multitype mt; mti < 2; mti++) \
if(mti) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t mtr = *(mtr_t*)mt; \
MTA(__VA_ARGS__) \
free(mt); \
} else \
mt
/* Return */
#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
This makes it possible to return up to four variables from a function and assign them to up to four variables. As an example, you can use them like this:
multitype (int,float,double) fun() {
int a = 55;
float b = 3.9;
double c = 24.15;
RETURN (a,b,c);
}
int main(int argc, char *argv[]) {
int x;
float y;
double z;
let (x,y,z) = fun();
printf("(%d, %f, %g\n)", x, y, z);
return 0;
}
This is what it prints:
(55, 3.9, 24.15)
The solution may not be as portable because it requires C99 or later for variadic macros and for-statement variable declarations. But I think it was interesting enough to post here. Another issue is that the compiler will not warn you if you assign them the wrong values, so you have to be careful.
Additional examples, and a stack-based version of the code using unions, are available at my github repository.
Use pointers as your function parameters.
Then use them to return multiple value.
By passing parameters by reference to function.
Examples:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Also by using global variables but it is not recommended.
Example:
int a=0;
void main(void)
{
//Anything you want to code.
}