passing array initial values to a C macro [duplicate] - c

This has been bugging me for some time, for example, if I'm trying to write this code:
// find the length of an array
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(int))
// declare an array together with a variable containing the array's length
#define ARRAY(name, arr) int name[] = arr; size_t name##_length = ARRAY_LENGTH(name);
int main() {
ARRAY(myarr, {1, 2, 3});
}
The code gives this error:
<stdin>:8:31: error: macro "ARRAY" passed 4 arguments, but takes just 2
Because it sees ARRAY(myarr, {1, 2, 3}); as passing ARRAY the argument myarr, {1, 2, and 3}. Is there any way to pass an array literal to macros?
EDIT: In some of the more complex macros I needed, I may also need to pass two or more arrays to the macro, so variadic macro does not work.

Yes, the {} aren't parenthesis for the preprocessor. You can simply protect the arguments by a dummy macro
#define P99_PROTECT(...) __VA_ARGS__
ARRAY(myarr, P99_PROTECT({1, 2, 3}));
Should work in your case. By that you have a first level of () that protects the , from being interpreted as argument separator. These () of the macro call then disappear on the expansion.
See here for more sophisticated macros that do statement unroling.

Related

C execute function with list of arguments

I need to evaluate function with list of arguments from array of arguments as in this example:
int compute(...) {
int n;
va_list params;
va_start(params, n);
// some custom computation with no "va" output
va_end(params);
}
And some array of int (which is dynamic array, don't rely on fixed size):
int arr[10] = {0, 1, 3, 7, 8, 1, 3, 5, 7, 9};
And I need to call compute like JS function compute.apply(this, arr)
I'm implementing some library with C that's why I need it.
In C++ this is std::apply but I want the same in C.
Thanks
In C++ this is std::apply but I want the same in C.
Since you want the same in C, you'll surely accept that you have to fulfill the same requirements, in particular, as a tuple supports std::get and std::tuple_size, their C equivalents. Now, as long as the arguments from the array are accessed in order from first to last, std::get can be implemented with va_…(), but just as the stdarg variable argument lists need some means of determining the amount of arguments (like a format string or an argument count), std::tuple_size cannot be implemented without such a means. You won't do without passing this information.

Possible to declare an array in function argument? [duplicate]

This question already has an answer here:
Why can't I pass constant arrays as arguments?
(1 answer)
Closed 4 years ago.
Is there some way to pass an array of ints into a function in C, like this:
func(int[]{1, 2, 3});
or like this?
func({1, 2, 3});
I am aware of the existence of va_list, but it's not quite what I am looking for.
It looks like you're looking for a compound literal (defined in C11 §6.5.2.5 Compound literals; also a feature in C99):
func((int[]){ 1, 2, 33, 491 });
A compound literal looks like a cast followed by a braced initializer for the type specified in the cast. The scope of the compound literal is to the end of the statement block in which it is introduced, so it will be valid for the entire block in which the call to func() is found. Consequently, it is valid for the whole of the call to func(). And the compound literal is a modifiable value.
We can validly quibble about the interface to the function not specifying how many values are in the array (so how does func() know how big the array is), but that is somewhat tangential to the idea of the compound literal notation.
The function itself is a perfectly ordinary function taking an array argument:
extern void func(int arr[]);
void func(int arr[])
{
…
}
Or, of course:
extern void func(int *arr);
void func(int *arr)
{
…
}
And (with the major caveat about how the function knows how big the array is), you could write:
void calling_func(void)
{
func((int[]){ 1, 2, 33, 491 });
int array[] = { 2, 99, 462, -9, -31 };
func(array);
}

Create a macro that can omit a line based on a parameter

I have the following lines of code, created by a database export program:
typedef struct _s8_VARB
{
unsigned char _byte[8];
} s8_VARB;
const s8_VARB varb00[] = {
mMM(1,25,22,12,0,0,0,0,27)
mMM(0,1,29,12,0,0,0,0,21)
mMM(1,1,36,12,0,0,0,0,22)
}
The mMM is a macro that I want to define with a functionality that will produce the following data during compilation:
const s8_VARB varb00[] = {
1,25,22,12,0,0,0,0,27,
1,1,36,12,0,0,0,0,22,
}
So it basically should check the 1st parameter. If it is 0, that complete line should omitted. If it is 1, all the parameters (except the 1st) should be 'put on the line', ending with a comma.
What I have tried is this:
#define COMMA ,
#define mMM(cond, a,b,c,d,e,f,g,h) (cond) ? (a),(b),(c),(d),(e),(f),(g),(h) COMMA :
But this is not working. Not even compiling, as gcc complains:
error: expected expression before ':' token
How should this macro definition should look like? Is this possible at all in C?
You can initialize an array with constant data only. A conditional statement is by definition not constant (even if it's known to the compiler at compile time).
Instead you could do it like this:
#define _mMM0(...)
#define _mMM1(...) {__VA_ARGS__},
#define mMM(cond, ...) _mMM##cond(__VA_ARGS__)
const unsigned char varb00[][8] = {
mMM(1,25,22,12,0,0,0,0,27)
mMM(0,1,29,12,0,0,0,0,21)
mMM(1,1,36,12,0,0,0,0,22)
};
I removed the struct and replaced it with its only member directly. In case C99 is not available, you can name every parameter as you used to do.
Here's a hackish solution. If the number of arguments is fixed and you can't use C99+, then you could list them explicitly instead of using ... and __VA_ARGS__.
#define mMM(x, ...) mMM##x(__VA_ARGS__)
#define mMM0(...)
#define mMM1(...) __VA_ARGS__,
The ## operator pastes the token mMM and the x argument together to form a new macro name -- either mMM0 or mMM1 -- which is then called with the remaining arguments. mMM0() in turn expands to nothing, and mMM1() expands to its arguments.
(The extra trailing comma after the last element won't be a problem by the way. int a[] = { 1, 2, 3, } is explicitly allowed syntax in C.)
As a side note, invoking a macro like
#define m(x) (x) ? 1 : 2
using e.g. m(0) will simply expand it to (0) ? 1 : 2. The ternary operator will not be handled in the preprocessor.

c macro, array definition as parameter

I have this method
foo_l(int *array, size_t l)
{
/*
code
*/
}
and I wrote this macro
#define foo(X) foo_l(X,sizeof(X)/sizeof(int))
So I can use them as follows
int main()
{
int a[]={1,2,3};
foo(a);
return 0;
}
and avoid writing the length of the array every time.
My question is, can I extend my macro so it can handle something like
foo_l((int[]){1,2,3}, 3);
with an array declared in the function parameter field?
Because foo((int[]){1,2,3}) doesn't work! I think that the problem is that the macro see (int[]){1,2,3} as a list of parameters and not as a unique parameter. Any Idea?
P.S. I'm pretty new to the macro world and I usually use c99.
When being passed to the preprocessor, the macro foo((int[]){1,2,3}) fails because the preprocessor believes it provided 3 parameters instead of 1:
foo((int[]){1,2,3});
// is believed to be:
// Start of macro: foo(
// Parameter 1: (int[]){1,
// Parameter 2: 2,
// Parameter 3: 3}
// End of macro: );
So it doesn't compile and gives something like:
a.c: In function ‘main’:
a.c:15:23: error: macro "foo" passed 3 arguments, but takes just 1
foo((int[]){1,2,3});
Adding another pair of parenthesis solves the problem:
// This shall work
foo(((int[]){1,2,3}));
EDITED:
Yes I guess this may not be a good design, since people like average programmers may be very likely to pass a pointer instead of an array type to your macro foo, and it would fail as #DwayneTowell points out.
Please be careful about this.
:)
What you have suggested is not a good idea, because it will fail in cases like the following:
int a[] = {1,2,3,4};
int *b = a;
foo(b); // becomes foo_l(b,sizeof(b)/(sizeof(int));
// probably becomes foo_l(b,1)
In general the size parameter will be wrong if the first parameter is a pointer to an array instead of the array itself. Usually the expression will evaluate to 1, when sizeof(int *)==sizeof(int), which is very common but required by the standard.

Passing array literal as macro argument

This has been bugging me for some time, for example, if I'm trying to write this code:
// find the length of an array
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(int))
// declare an array together with a variable containing the array's length
#define ARRAY(name, arr) int name[] = arr; size_t name##_length = ARRAY_LENGTH(name);
int main() {
ARRAY(myarr, {1, 2, 3});
}
The code gives this error:
<stdin>:8:31: error: macro "ARRAY" passed 4 arguments, but takes just 2
Because it sees ARRAY(myarr, {1, 2, 3}); as passing ARRAY the argument myarr, {1, 2, and 3}. Is there any way to pass an array literal to macros?
EDIT: In some of the more complex macros I needed, I may also need to pass two or more arrays to the macro, so variadic macro does not work.
Yes, the {} aren't parenthesis for the preprocessor. You can simply protect the arguments by a dummy macro
#define P99_PROTECT(...) __VA_ARGS__
ARRAY(myarr, P99_PROTECT({1, 2, 3}));
Should work in your case. By that you have a first level of () that protects the , from being interpreted as argument separator. These () of the macro call then disappear on the expansion.
See here for more sophisticated macros that do statement unroling.

Resources