I found this macro #define TIMES(x) for(int i1=0;i1<x;i1++)very pratical to shorten the code text. But I do not know how to write such a macro when I have nested loops and even I do not know if it is possible. The idea is the following. Is it possible to write this code
for(int i1=0;i1<5;i1++)
for(int i2=0;i2<3;i2++)
for (int i3=0;i3<7;i3++)
/* many nested `for` loops */
{
/* some code, for example to print an array printf("%d \n",a[i1][i2][i3]) */
}
as
TIMES(5) TIMES(3) TIMES(7) ....
{
/* some code, for example to print an array printf("%d \n",a[i1][i2][i3]) */
}
with a sort of "recursive" macro that detects all TIMES and replaces them by a forloop with i1, i2, i3, ... i'n' loop counters ?
This is very bad practice, don't do this. Other C programmers are perfectly aware of for loops, but they are completely oblivious to your private, secret macro language. In addition, function-like macros like these have poor type safety and should only be used as the last resort.
The correct solution is not to use a macro, but a function. If you wish to utilize proper generic programming, you could write it as follows:
typedef void callback_t (int data);
void traverse (size_t n, int data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(data[i]);
}
}
Where callback is a function pointer provided by the caller, which contains the actual functionality. Similar to the loop body in your macro.
Full example:
#include <stdio.h>
typedef void callback_t (int data);
void traverse (size_t n, int data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(data[i]);
}
}
void print (int i)
{
printf("%d ", i);
}
int main (void)
{
int array [5] = {1, 2, 3, 4, 5};
traverse(5, array, print);
}
EDIT:
In the above example, the data type was int. But since it is generic programming, you can do some tweaks and swap it for any other data type, such as an array or a struct. The catch then is that you must pass the parameter to the callback through a pointer, instead of passing it by value. Example:
#include <stdio.h>
/* Generally it is bad practice to hide arrays behind typedefs like this.
Here it just done for illustration of generic programming in C. */
typedef int data_t[3];
typedef void callback_t (data_t* data);
void traverse (size_t n, data_t data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(&data[i]);
}
}
void print_array (int(*array)[3])
{
int* ptr = *array;
printf("{%d %d %d}\n", ptr[0], ptr[1], ptr[2]);
}
int main (void)
{
int array [2][3] = { {1, 2, 3}, {4, 5, 6} };
traverse(2, array, print_array);
}
This closely follows Lundin's solution, but is refactored into something more generalized.
To generically step through elements, you can leave your arguments as void *, similar to qsort and bsearch.
typedef void cb_type (void *base, size_t sz);
void
traverse (void *base, size_t n, size_t sz, cb_type *cb) {
char *p = base;
for (size_t i = 0; i < n; ++i) {
cb(p + i*sz, sz);
}
}
The callback is passed the sizeof of the element. The callback function is supposed to be aware of the underlying type of the object, so it can properly deduce which dimension is being traversed. For example, if traversing a int[4][5][6]:
int array[4][5][6];
traverse(array, 4, sizeof(*array), print_456);
And the print function could look like this:
void
print_456 (void *base, size_t sz) {
if (sz == 5 * 6 * sizeof(int)) {
traverse(base, 5, 6*sizeof(int), print_456);
puts("");
} else if (sz == 6 * sizeof(int)) {
traverse(base, 6, sizeof(int), print_456);
puts("");
} else
printf("%d ", *(int *)base);
}
Try It Online
I finally succeed in writing this macro. I found most of the informations to do that in this very good article (http://jhnet.co.uk/articles/cpp_magic). The following posts (Can we have recursive macros?, Is there a way to use C++ preprocessor stringification on variadic macro arguments?, C++ preprocessor __VA_ARGS__ number of arguments, Variadic macro trick, ...) help me also a lot.
This answer is intended to answer question. It does not address the question of macro and good programming pratices. It is another subject.
This is the code
#define SECOND(a, b, ...) b
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define FIRST(a, ...) a
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first,__VA_ARGS__) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define PP_NARG(...) \
PP_NARG_(,##__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
z,_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#define TIMES(...) EVAL(MAP(TIME2FOR,__VA_ARGS__))
#define TIME2FOR(x,...) \
for(int CAT(i,PP_NARG(__VA_ARGS__))=0; \
CAT(i,PP_NARG(__VA_ARGS__))<x; \
CAT (i,PP_NARG(__VA_ARGS__))++)
main() {
int a[3][2][4];
TIMES(3,2,4) a[i2][i1][i0]=i2*100+i1*10+i0;
TIMES (3,2,4) printf("a[%d][%d][%d] : %d\n",i2,i1,i0,a[i2][i1][i0]);
TIMES (3,2,4) {/* whatever you want : loop indexes are ...,i2,i1,i0 */}
}
It turned out to be more difficult than I thought it would be.
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.
}
I want a C function that I can pass a structure to and it will return the number of fields/members within the structure.
At the moment I've found the easiest way is to just make a table and add to the table anytime I add a struct to any of the programs.
I guess I'm experiencing an XY problem (per the suggestions) So anyway, the reason why I would have use for this type function is because I'm wanting to send structures over a socket and to avoid the whole serialization process the way in which i'm trying to do this is by adding delimiters to the structure's field members. Like this:
0x001 --> hdrdata --> 0x003 --> hdrdata --> 0x017 --> 0x002 --> bodydata --> 0x003 --> bodydata --> 0x003 --> bodydata --> 0x004
As you can see there may be 1 bodydata or there may be 10 bodydata etc. The only other thing I can quickly think to do is add a member to my structs that would inform my header how many 'bodydata' transmissions will be coming through so the client knows how many 0x003's to expect.
Or (and i'm not asking for an answer to this but feel free if you are so inclined) can anyone recommend a better protocol design for sending structures over socket in unix? Most of this project is for my own learning so i'm not interested in using an already complete library/package solution otherwise i'd just be writing this in another language in the first place.
This is very very ugly, but the only thing I can think of is an X-Macro:
#include <stdio.h>
#define MEMBERS \
X(char a) \
X(float b) \
X(double c)
struct T {
#define X(x) x;
MEMBERS
#undef X
};
int main(void)
{
size_t n = 0
#define X(x) +1
MEMBERS
#undef X
;
printf("%zu members\n", n);
return 0;
}
This expands to:
#include <stdio.h>
struct T {
char a;
float b;
double c;
};
int main(void)
{
size_t n = 0+1+1+1;
printf("%zu members\n", n);
return 0;
}
As pointed out by #HAL9000 in comments, you can generate both (the struct and the counter) at the same time in this way:
#include <stdio.h>
#define GENERATE_STRUCT(s) s;
#define GENERATE_SCOUNT(s) +1
#define set_struct(name) \
struct name { \
name##_members(GENERATE_STRUCT) \
}; \
\
size_t name##_count(void) \
{ \
return 0 \
name##_members(GENERATE_SCOUNT) \
; \
}
#define foo_members(X) \
X(char a) \
X(float b) \
X(double c)
set_struct(foo)
int main(void)
{
printf("%zu members\n", foo_count());
return 0;
}
In this case is expanded to:
#include <stdio.h>
struct foo {
char a;
float b;
double c;
};
size_t foo_count(void)
{
return 0+1+1+1;
}
int main(void)
{
printf("%zu members\n", foo_count());
return 0;
}
Finally, another implementation provided by #Lundin using an enum instead of a variable:
#include <stdio.h>
#define MEMBERS \
/* type name */ \
X(char, a) \
X(float, b) \
X(double, c) \
struct T {
#define X(type, name) type name;
MEMBERS
#undef X
};
enum
{
#define X(type, name) dummy_##name,
MEMBERS
#undef X
MEMBER_COUNT
};
int main(void)
{
printf("%d members\n", MEMBER_COUNT);
return 0;
}
Expands to:
#include <stdio.h>
struct T {
char a;
float b;
double c;
};
enum {
dummy_a,
dummy_b,
dummy_c,
MEMBER_COUNT
};
int main(void)
{
printf("%d members\n", MEMBER_COUNT);
return 0;
}
I had a array in c:
int array[] = {1, 2, 3, 4};
and I had a function's protype like this:
int add_all(int a, int b, int c, int d);
But how can I pass the array's all elements as the function's parameter at one time?
I know in python, this can be done like this:
array=[1,2,3,4]
add_all(*array)
Could someone tell me how to achieve the same effect in C?
Try this:
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/control/while.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/push_back.hpp>
#include <boost/preprocessor/tuple/reverse.hpp>
#define ARRAY_ELEM(x,n) x[n]
#define PRED(n, state) BOOST_PP_TUPLE_ELEM(3, 1, state)
#define OP(d, state) \
OP_D( \
d, \
BOOST_PP_TUPLE_ELEM(3, 0, state), \
BOOST_PP_TUPLE_ELEM(3, 1, state), \
BOOST_PP_TUPLE_ELEM(3, 2, state) \
)
#define OP_D(d, res, c, arr_name) \
( \
BOOST_PP_TUPLE_PUSH_BACK(res,ARRAY_ELEM(arr_name,BOOST_PP_DEC(c))), \
BOOST_PP_DEC(c), \
arr_name \
) \
#define UNPACK_REVERSE(ARR_NAME,N) \
BOOST_PP_TUPLE_ELEM( \
3, 0, \
BOOST_PP_WHILE(PRED, OP, ((ARRAY_ELEM(ARR_NAME,BOOST_PP_DEC(N))), \
BOOST_PP_DEC(N),ARR_NAME) ) \
)
/*The macro to be called*/
#define UNPACK(ARR_NAME,N) \
BOOST_PP_TUPLE_REVERSE(UNPACK_REVERSE(ARR_NAME,N))
And here's a usage example:
void print3(int x, int y, int z){
printf("%d,%d,%d\n",x,y,z);
}
int main(){
int z[3]={1,2,3};
print3 UNPACK(z,3);
return 0;
}
This macro uses Boost's Preprocessor library in a loop to generate and expand the array elements in a tuple. Hope it helps.
Use this:
int add_all(array, 4);
When you call a function, and you try to pass it an array, this array
will be converted to a pointer to the first element of the array.
Function prototype
int add_all(int[] , int size);
or
int add_all(int* , int size);
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)
Suppose I would like to use the C Preprocessor to define a family of function, for which only a parameter type changes. Let's take for example allocation functions with parameters:
#include <stdint.h>
#include <stdio.h>
#define type_vector(t) \
t * t##vector(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = int32_tvector(10, 12);
return 0;
}
This works fine.
Now, suppose I would like to have shorter names for type in the function names: i8 instead of int8_t, i32 instead of int32_t, etc.
I do not want to add a second parameter to the macro function declaration, but instead have a single definition of "short" type names.
Basically, the first thing I wrote was:
#define sn_int8_t i8
#define sn_int32_t i32
#define sn_int64_t i64
#define sn(t) sn_##t
#define type_vector(t) \
t * sn(t)##vector(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = i32vector(10, 12);
return 0;
}
However, this does not compile, giving the following error:
error: pasting ")" and "vector" does not give a valid preprocessing token
t * sn(t)##vector(int32_t nl, int32_t nh) \
As far as I understood, the problem is due to having the ")" and the "#" side by side.
So I did the following:
#define sn_int8_t(f) i8##f
#define sn_int32_t(f) i32##f
#define sn_int64_t(f) i64##f
#define sn2(t,f) sn_##t(f)
#define type_vector(t) \
t * sn2(t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = i32vector(10, 12);
return 0;
}
And this works fine again.
Now, suppose I would like to add a prefix to the function name, e.g. "remote_".
Simply putting
#define type_vector(t) \
t * remote_##sn2(t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
does not work, as sn2 is not expanded. So I tried this:
#include <stdint.h>
#include <stdio.h>
#define sn_int8_t(f) i8##f
#define sn_int32_t(f) i32##f
#define sn_int64_t(f) i64##f
#define sn2(t,f) sn_##t(f)
#define short_name(n,t,f) n##_##sn2(t,f)
#define remote_type_vector(t) \
t * short_name(remote,t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; \
return v; \
}
remote_type_vector(int8_t)
remote_type_vector(int32_t)
remote_type_vector(int64_t)
int main() {
int32_t * p;
p = remote_i32vector(10, 12);
return 0;
}
Basically, this does not work because the macro sn2 is not expanded, giving me declarations like:
int32_t * remote_sn2(int32_t,vector)
Is there any way to do that?
Note: I do not want to use C++ templates.
Here's a unified solution that should work for all of your needs:
#define sn_int8_t(p,s) p##i8##s
#define sn_int32_t(p,s) p##i32##s
#define sn_int64_t(p,s) p##i64##s
#define sn2(t,p,s) sn_##t(p,s)
#define type_vector(t) \
t * sn2(t,,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
#define remote_type_vector(t) \
t * sn2(t,remote,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
remote_type_vector(int8_t)
remote_type_vector(int32_t)
remote_type_vector(int64_t)