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.
Related
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.
I have a question regarding two-dimensional arrays in C. I know now (from direct compiler experience) that I can't initialize such an array analogously to one-dimensional arrays like this:
int multi_array[][] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
> compiler output:
gcc -o arrays arrays.c
arrays.c: In function ‘main’:
arrays.c:8:9: error: array type has incomplete element type
The closest solution that works is to provide the number of columns explicitly like this:
int multi_array[][5] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
My question is: can it be done neatly without supplying the number explicitly (which after all the compiler should be able to infer itself)? I'm not talking about manually constructing it with malloc or something but rather something close to what I tried.
Also, can someone knowledgeable about C compilers explain from a low-level perspective why my initial attempt does not work?
I used plain gcc with no non-standard options to compile the code.
Thanks
2D arrays in C are stored in contiguous memory locations. So if you do not provide the number of rows or the number of columns, how will the compiler know how many rows and column there are?
For a row major matrix, rows contents are at contiguous memory positions. So you need to specify at least the number of columns. Similarly for a column major matrix, you need to specify at least the number of rows. Whether it is row major or column major is defined by architecture. It seems that what you have is a row major architecture.
You can do this using the C99 compound literal feature.
A partial idea is that the length of an initializer list can be determined like this:
sizeof (int[]){ 1, 2, 3, 4, 5 } / sizeof(int)
We need a workaround for the fact that the only way you can pass an argument containing a comma to a macro is to put parentheses around (part of) the argument:
#define ROW(...) { __VA_ARGS__ }
Then the following macro deduces the second dimension from the first row:
#define MAGIC_2DARRAY(type, ident, row1, ...) \
type ident[][sizeof (type[])row1 / sizeof (type)] = { \
row1, __VA_ARGS__ \
}
It only works if there are at least two rows.
Example:
MAGIC_2DARRAY(int, arr, ROW(7, 8, 9), ROW(4, 5, 6));
You probably do not want to use this in a real program, but it is possible.
For passing this kind of array to functions, the C99 variable length array feature is useful, with a function like:
void printarr(int rows, int columns, int array[rows][columns]) { ... }
called as:
printarr(sizeof arr / sizeof arr[0], sizeof arr[0] / sizeof arr[0][0], arr);
Not a direct answer to those questions in the original post, I just want to point out that what the asker propose may be not such a good or useful idea.
The compiler indeed can infer from
int multi_array[][] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
the structure of multi_array.
But when you want to declare and define a function (this declaration and definition could be in another compilation unit or source file) that supposes to accept multi_array as one of its argument, you still need to do something like
int foo(..., int multi_array[][COL], ...) { }
Compiler needs this COL to do proper pointer arithmetic in foo().
Usually, we define COL as a macro that will be replaced by an integer in a header file, and use it in the definitions of multi_array and foo():
int multi_array[][COL] = { ... };
int foo(..., int multi_array[][COL], ...) { }
By doing this, it is easy to make sure they are the same. And let compiler to infer the structure of multi_array according to its initialization, when you give it a wrong initialization, you actually introduce a bug in your code.
No you can't do it. If you even don't initialize, you can't define an int array[][];
Create a structure with 1d arrays. However, if you follow this method you can create new arrays but it will be a function call to change sizes and values. A dynamic matrix approach could come close to solving your issue.
I'm having trouble understanding why incrementing the pointers in pnArryCpy below is incorrect. I figured out how to copy the array using pointer notation a different way, but I need to understand what's wrong with this (e.g., (* tgt_s)++; where int (*tgt_s)[cs]), and why tgt_s is an lvalue (e.g., tgt_s++ is valid) but *tgt_s is not (really) an lvalue.
int main(void)
{
int arr1[2][4] = { {1, 2, 3, 4}, {6, 7, 8, 9} };
int arr2[2][4];
pnArrCpy(4, arr1, arr2, arr2+2); // copies 2d array using pointer notation
// - this is where the problem is.
printarr(2, 4, arr2); // this just prints the array and works fine - not at issue
putchar('\n');
return 0;
}
void pnArrCpy(int cs, int (*src)[cs], int (*tgt_s)[cs], int (*tgt_e)[cs])
{
while (tgt_s < tgt_e)
{
**tgt_s=**src;
(* tgt_s)++; // older versions of gcc warn "target of assignment not really
// an lvalue", latest versions throw an error
(* src)++; // but no errors are runtime
}
return;
}
// trucated rest of program since it's not relevant, just the function for printing
// the array
Under the older gcc, the program compiles and displays the correct results, namely:
1 2 3 4
6 7 8 9
Mac OS 10.8.2
gcc 4.7.2 gave me the error
gcc 4.2.1 was only giving me warnings
Thank you!!
EDIT: Reason I'm using variable length arrays: this function is part of another program, and this one is just a driver I was using to troubleshoot pnArrCpy. In the actual program, the array dimensions and contents are user defined, hence use of VLA.
The thing is:
int (*tgt_s)[cs] is a pointer to an array. Take a few seconds to think about that, it's a bit of an exotic pointer
*tgt_s is therefore an array
arrays are not modifiable lvalues
What makes it hardest to understand is the way you're using the C99 feature of passing cs and then using it in the parameter list.
If you want to learn more about VLAs as function arguments, check out this excellent post.
I thought that the function removes the parameters from the stack after it's done, but a function like printf removes a variable number of parameters from the stack when it's called.
How does it know how many parameters to remove from the stack? Is there a secret argument to specify how many arguments are passed?
Thanks
The C calling convention specifies that is the caller and not the callee the one responsible from popping the parameters from the stack. That's why functions with a variable argument list must be cdecl. So,
I thought that the function removes the parameters from the stack after it's done.
That's only true for certain calling conventions, it isn't true for the C calling convention.
How does it know how many parameters to remove from the stack? Is there a secret argument to specify how many arguments are passed?
It doesn't, and no there is no secret argument.
The caller function will clean the stack (in the correct calling convention). The compiler will generate the code for that. The compiler is the one knowing exactly how many arguments you passed on the arguments list, because, well, it compiled it..
The calling code cleans up the stack, and it's up to the called function to correctly determine that there is "enough" arguments have been passed for whatever it wants to do. This doesn't have to be an argument as such, it could be something like this:
int sum(int first, ...)
{
int s = first;
int v;
va_list va;
va_start(va, first);
while (v = va_arg(va, int) != -1)
{
sum += v;
}
va_end(va);
return sum;
}
x = sum(1, 2, 3, -1);
y = sum(1, 2, 3, 4, 5, 6, 7, 8, 9, -1);
Link to how many arguments in varargs function
I am trying to write a function that takes an array of an variable size in c.
void sort(int s, int e, int arr[*]){
...
}
It says that for variable length arrays, it needs to be bounded in the function declaration. What does that mean? I am using xcode 4.0, with the LLVM compiler 2.0.
Thanks for the help.
As I see that no one answers the real question, here I give mine.
In C99 you have variable length arrays (VLA) that are declare with a length that is evaluated at run time, and not only at compile time as for previous versions of C. But passing arrays to functions is a bit tricky.
A one dimensional array is always just passed as a pointer so
void sort(size_t n, int arr[n]) {
}
is equivalent to
void sort(size_t n, int *arr){
}
Higher dimensions are well passed through to the function
void toto(size_t n, size_t m, int arr[n][m]){
}
is equivalent to
void toto(size_t n, size_t m, int (*arr)[m]){
}
With such a definition in the inside of such a function you can access the elements with expressions as arr[i][j] and the compiler knows how to compute the correct element.
Now comes the syntax that you discovered which is only useful for prototypes that is places where you forward-declare the interface of the function
void toto(size_t, size_t, int arr[*][*]);
so here you may replace the array dimension by * as placeholders. But this is only usefull when you don't have the names of the dimensions at hand, and it is much clearer to use exactly the same version as for the definition.
void toto(size_t n, size_t m, int arr[n][m]);
In general for a consistent use of that it is just important that you have the dimensions first in the the parameter list. Otherwise they would not be known when the compiler parses the declaration of arr.
If you're not using the C99 variable length arrays (it appears you are, so see below), the usual solution is to pass in a pointer to the first element, along with any indexes you want to use for accessing the elements.
Here's a piece of code that prints out a range of an array, similar to what you're trying to do with your sort.
#include <stdio.h>
static void fn (int *arr, size_t start, size_t end) {
size_t idx;
for (idx = start; idx <= end; idx++) {
printf ("%d ", arr[idx]);
}
putchar ('\n');
}
int main (void) {
int my_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
fn (my_array, 4, 6);
return 0;
}
This outputs elements four through six inclusive (zero-based), giving:
5 4 3
A couple of points to note.
Using my_array in that function call to fn automatically "decays" the array into a pointer to its first element. This actually happens under most (not all) circumstances when you use arrays, so you don't have to explicitly state &(my_array[0]).
C already has a very good sort function built in to the standard library, called qsort. In many cases, that's what you should be using (unless either you have a specific algorithm you want to use for sorting, or you're doing a homework/self-education exercise).
If you are using real VLAs, you should be aware that the [*] construct is only valid in the function prototype, not in an actual definition of the function.
So, while:
void xyzzy(int, int[*]);
is valid, the following is not:
void xyzzy(int sz, int plugh[*]) { doSomething(); }
That's because, while you don't need the size parameter in the prototype, you do very much need it in the definition. And, since you have it, you should just use it:
void xyzzy(int sz, int plugh[sz]) { doSomething(); }
The gcc compiler actually has a reasonably clear error message for this, far better than the "needs to be bounded in the function declaration" one you saw:
error: ‘[*]’ not allowed in other than function prototype scope
What you want to do it make your argument an int *; pass in the length of the array (which the caller presumably knows, but this routine does not) as a separate argument. You can pass an array as such an argument.
The usage of * inside of array brackets for variable-length arrays is limited to prototypes, and serves merely as a placeholder. When the function is later defined, the array's size should be stored in a variable available at either file scope or as one of the parameters. Here's a simple example:
void foo(int, int[*]);
/* asterisk is placeholder */
void foo(int size, int array[size]) {
/* note size of array is specified now */
}