Variadic function in C99 to deallocate several arrays? - c

Currently, I have a very simple function to deallocate array of doubles in my program:
void deallocate(double** array)
{
free(*array);
}
I would like this function to be variadic in order to take several arrays, and free them one after another. I've never written a variadic function, and as there may exist tricks with pointers I would like to know how to do that.

Don't do this with a variadic function, this concept should be retired. In particular it makes no sense at all for something that is to receive arguments of all the same type, void*.
Just have a simple function, first that receives an array of pointers
void free_arrays(void* a[]) {
for (size_t i = 0; a[i]; ++i) free(a[i]);
}
Then you can wrap that with a macro like that
#define FREE_ARRAYS(...) free_arrays((void*[]){ __VA_ARGS__, 0 })
This supposes that none of your pointers is already 0, since the processing would stop at that point.
If you'd have a need to have that working even if some of the pointers are 0, you'd have to pass the number of elements as a first parameter to your function. This is a bit tedious but can be determined in the macro, too.
void free_arrays0(size_t n, void* a[]) {
for (size_t i = 0; i < n; ++i) free(a[i]);
}
#define FREE_ARRAYS0(...) \
free_arrays( \
sizeof((void*[]){ __VA_ARGS__})/sizeof(void*), \
(void*[]){ __VA_ARGS__} \
)

You can do it like this:
void deallocate(double *p, ...)
{
va_list ap;
va_start(ap, p);
do {
free(p);
p = va_arg(ap, double *);
} while (p);
va_end(ap);
}
Call as deallocate(p1, p2, p3, (double *)NULL). You need the NULL (or some other value) as a sentinel to signal the end of the argument list; none of the other pointers should be NULL or the loop will stop prematurely.
I'm not saying that this is a good idea, though: varargs functions have their use cases, but they're error-prone with pointers because some implicit conversions don't take place (because the compiler doesn't know the type of the arguments beyond the first).

Related

How to pass each value of an array as parameters to a function?

I have the following function that accepts a varying number of integer parameters and returns the sum.
int sum(int a, ...){
va_list nums;
va_start(nums, a);
int res=0;
for(int i=0; i<a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
I need to pass each value of the array as a parameter to the function rather than passing the array itself. The array can be of varying length leading to a varying length of arguments to pass too.
printf("The sum is: %d", sum(size, args[0], args[1], ```need all elements of args[] array here```));
To put forth some perspective, I'm using this sum function to understand how I can go about doing this. It would be helpful to know how to achieve this in a more general setting rather than this exact function.
Please let me know if you need any more information.
Please do look at this question, which is similar, however, I require a solution in C.
The short answer is that there's no way to do exactly this in the C language. There is no ES6-like spread operator in C, nor similar functionality. I don't think there's any particular reason why they couldn't (you would just have to push more arguments onto the stack); they just never made one.
However, there are various other things you can do:
If variadic arguments were already passed into the function calling your function, you can pass along the va_list to a function declared to take a va_list. See Passing variable arguments to another function that accepts a variable argument list
As #JonathanLeffer suggests, the most natural way to write this code in C is by constructing an array of what "would be" your variadic arguments, and passing that into a function that expects an array (well, technically, a pointer, because arrays decay to pointers). For example:
int sum_array(int a, int nums[]){
int res=0;
for(int i=0; i<a; i++) {
res += nums[i];
}
return res;
}
In certain circumstances, it may be more convenient for a function like sum_array to take only the nums array/pointer, which would itself indicate the end of the array with a 0 or -1 value in the last slot. This is just another convention for indicating the end, which the caller has to set up.
You could then, if you really wanted to, write a variadic function that collects its arguments into an array and calls sum_array, if you want a variadic version as well. (Of course, you could also just implement the variadic and array versions separately, but for nontrivial functions it may be a pain to implement them twice.)
int sum_variadic(int a, ...){
va_list nums;
va_start(nums, a);
int arr[a];
for(int i=0; i<a; i++) {
arr[i] = va_arg(nums, int);
}
va_end(nums);
return sum_array(a, arr);
}
you could also use a variadic macro for the same purpose:
#define sum_macro(size, ...) sum_array(size, (int[]){__VA_ARGS__})
In summary: going from variadic to array in C is trivial, going from array to variadic is impossible.
You can also use extensions to the C language to do it anyway, as described in Passing a dynamic set of variadic arguments to a C function and In C, given a variable list of arguments, how to build a function call using them?, which #KamilCuk linked to.
You can avoid passing the number of arguments explicitly by using a variadic macro that constructs a compound literal array instead of a vararg function:
#include <stdio.h>
#define sum_int(...) (sum_int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int), (int[]){__VA_ARGS__})
int (sum_int)(size_t count, const int *a) {
int sum = 0;
for (size_t i = 0; i < count; i++) {
sum += a[i];
}
return sum;
}
int main() {
printf("sum = %d\n", sum_int(1, 2, 3));
return 0;
}
This approach can be used for any purpose, as long as the types of the variable arguments are converted implicitly to the array type.
If you want to pass just the arguments to your sum function without changing its definition, you can use a variation of the macro:
#include <stdio.h>
int sum(int a, ...) {
va_list nums;
va_start(nums, a);
int res = 0;
for (int i = 0; i < a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
#define sum(...) (sum)((int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)
int main() {
printf("sum = %d\n", sum(1, 2, 3));
return 0;
}
Note however that there is no type checking with this approach and sum(1, 2.0, 3) would have undefined behavior.

Variadic function works in Win32 but not in Win64

I have been using the following function for quite some time:
void AddRow(int iNumOfColumns,...)
{
int* pValuePerColumn = (int*)&iNumOfColumns+1;
for (int i=0; i<iNumOfColumns; i++)
{
// Do something with pValuePerColumn[i]
}
}
Now it turns out that it crashes on Win64 for one of our customers.
I do not have a 64-bit platform at hand, but I am assuming that the reason is:
When the function is invoked, the arguments are pushed into the stack as 64-bit values.
Under this assumption, I believe that replacing int* with size_t* should resolve the problem.
My questions are:
Is my analysis correct?
Is my solution correct?
Is there a more "conventional" way for solving this?
Derefencing a pointer to one past the last element of the array, or a non array object, is undefined behavior:
int* pValuePerColumn = (int*)&iNumOfColumns+1;
...
pValuePerColumn[i]
Changing the type to size_t is irrelevant for this problem.
The only correct way of using variable arguments are macros provided in stdarg.h.
You should use varargs to access extra parameters in portable way. Look for va_list docs. Probably your code should look next
void AddRow(int iNumOfColumns,...)
{
va_list ap;
va_start(ap, iNumOfColumns);
for (int i=0; i<iNumOfColumns; i++)
{
int col = va_arg(ap, int);
// Do something with col
}
va_end(ap);
}
And as I remember on Win64 first four integer args are passed via registers, not via the stack, so tricks with pointers won't work.

Create a C function that accepts parameters of different data types

I'm relatively new to the C programming language, and I'm trying to figure out how to create a function that can accept different types of data as parameters. The function is supposed to count and return the number of elements in a character or integer array. I already have two separate functions that will do this, but I would really like to be able to use one function for both tasks. Is there a way to do this in C?
Thanks in advance!
There is no standard function overloading in C (nor are there templates), but you could probably look into "printf-like" functions (or variadic functions) and maybe they can do what you need. If anything they allow for a flexible parameter list.
There is an example here of such a function that takes a variable size integer array.
Perhaps you could have a function signature such as void iterate(const char* format, ...); that you use in the following ways:
iterate("char", some_char_array); // for char arrays/strings
Or
iterate("int", some_int_array); // for integer arrays
Aniket makes a good point though, how do you count the elements in an integer array? If you pass an int array as an argument, you would need to pass the size too which defeats the purpose of counting the elements in the array (as you already know that i.e. the size).
I assume you don't know the size but you have a terminator value in the array (such as -1).
I've hacked something quick that kinda does what you need with the above assumption in mind.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int iterate(const char* format, ...)
{
va_list ap;
va_start(ap, format);
if (strcmp(format, "char") == 0)
{
char* array = va_arg(ap, char*);
va_end(ap);
return strlen(array);
}
else if (strcmp(format, "int") == 0)
{
int j = -1;
int* int_array = va_arg(ap, int*);
while (int_array[++j] != -1)
;
va_end(ap);
return j;
}
va_end(ap);
return 0;
}
int main()
{
printf("%d\n", iterate("char", "abcdef"));
int arr[] = {5, 4, 3, 2, 1, 0, -1};
printf("%d\n", iterate("int", arr));
return 0;
}
This prints:
$ ./a.out
6
6
So, let's assume your two functions are called sizeof_char_array and sizeof_int_array.
In C11, there is a new feature called "generic selection" that will let you do what you want with a relatively simple macro:
#define sizeof_array(X) \
_Generic (*(X), \
char: sizeof_char_array, \
default: sizeof_int_array) (X)
(I don't even have a C11 implementation to test this against, so caveat emptor!)
Prior to C11, this was sometimes accomplished with a macro using regularly named functions. You can define a macro that will call one function or the other depending on a macro argument hint:
#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x)
int a[] = { 1, 2, 3, 4, -1 };
char b[] = "abc";
sizeof_array(int, a); /* macro expands to sizeof_int_array(a) */
sizeof_array(char, b); /* macro expands to sizeof_char_array(b) */
If the input argument is truly an array, you can use a macro to compute its size directly:
#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0))
In the case of an array, the following expression is true:
(void *)arr == &arr
Because the address of an array has the same location in memory as the address of its first element.
So, the macro computes: sizeof(arr)/sizeof(arr[0]). Since the sizeof operator reports the size in bytes of its argument, the computed expression results in the number of elements in the array. However, if you are using a sentinel to compute the length, the ARRAY_SZ macro will result in a size at least one larger than the length found traversing the array for the sentinel.
In the case that the argument is not an array, then the expression results in a divide by 0 exception.
The answer is quite simple. You do need a function for this task. Just try this piece of code
#define len(array) sizeof(array)/sizeof(*array)
and that's it.
Important note: As pointed out in the comments, this will not work for dynamically allocated arrays.
You should make your function arguments take in a void * type. This way, you can pass in different types of data, and type-cast it to the one you want. However, you do need to watch out because there is no guaranteed way to correctly 'guess' the type that a void* points to.
In either case, you will need some sort of type-inferencing system to tell the C compiler which function to call. Which means, you will need to know, before-hand the type of array you might send in as a parameter to this "super function" of yours.
There is no "auto-type-inferencing" in C that can let you reflect upon the type of data at runtime. Better yet, you might have to write your own runtime environment for this to happen.
A slightly trivial hackish way to do this:
#include <stdio.h>
size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes)
{
return sizeOfTheArrayInBytes/sizeOfOneElementInArray;
}
int main(int argc, char *argv[])
{
char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'};
int iArr[5] = {10,20,30,40,50};
printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)),
GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr)));
return 0;
}
It's not really possible, but you can make a tagged union
typedef struct {
union {
ssize_t i;
double d;
char *s;
} unknown;
char identity;
} Dynamic;
Or you can use a void pointer:
typedef struct {
void *unknown;
char identity;
} Dynamic;

Standard way to manipulate variadic arguments?

This is a weird question, but is there a standard way to manipulate the contents of a va_list before passing it to another function? For instance, suppose I have two functions, sum and vsum:
int vsum(int n, va_list ap) {
int total = 0;
for (int i = 0; i < n; ++i) {
total += va_arg(n, int);
return total;
}
int sum(int n, ...) {
va_list ap;
va_start(ap, n);
int total = vsum(n, ap);
va_end(ap);
return total;
}
If I call sum as sum(4, 1, 2, 3, 4), I expect to get the result 10. Now let's suppose that instead of calling vsum directly, sum calls an intermediate function, vsum_stub which does the following:
int vsum_stub(int n, va_list ap) {
va_list temp_ap;
va_copy(temp_ap, ap);
for (int i = 0; i < n; ++i) {
int *arg = &va_arg(ap, int);
*arg += 2;
}
va_end(temp_ap);
return vsum(n, ap);
}
Now when I call sum(4, 1, 2, 3, 4), I should get back the result 20, since vsum_stub increments all of the values in the va_list by 2. This doesn't compile of course since you can't take the address of the result of va_arg. Is there another way to do this though? I'm working in C99.
Background:
I'm working on a library that does some pointer translation so that data may be stored on the heap in a more efficient format. Programs are compiled with a custom transformation which converts calls to library functions like printf to my own stub functions (e.g., hc_printf). hc_printf needs to translate any pointer arguments (strings intended for %s) before passing the arguments to the real printf function.
Edit: Here's a code example. Let's say we have a string foo. foo is dynamically allocated with a modified version of malloc which returns a fake pointer. The compiler modifies the program so that it can deal with fake pointers. So this works:
char *foo = fake_malloc(4);
fake_strcpy(foo, "foo");
I want to write a fake_vprintf function like this (in pseudocode):
int fake_vprintf(const char *format, va_list args) {
for each pointer argument p in args
translate p to q, a real pointer to contiguous memory
replace p with q in args
}
return vprintf(format, args);
}
The program would call fake_vprintf just like the original vprintf using the fake pointer. fake_vprintf translates the fake pointer to a real pointer that the real vprintf can use.
Aha, as I understand, your problem is creating a new va_list argument to pass on to the standard vprintf functions. Which in turn, will require you to modify each member of the list. However, since there is no element wise fetch/edit/insert operation for such a list you are stuck.
I don't really see any way of doing this. Of course, you can create a vprintf apply the transformations in situ, one argument at a time. My suggestion will be: Reimplement all such standard library functions -- at any rate you are writing wrappers. This involves some work, but you are already doing a part of it with hc_printf etc, so why not go the whole distance (and guess what save on a function call!).
You probably can't use va_list in a platform-agnostic way. You'll have to look at how your environment defines a va_list in stdarg.h, and then write your own tools to work with it.
For example, if a va_list is just a (char *), you can do all sorts of things with it.
// add 1000 to the integer stored on the stack and advance va_list
*(int *)va_list += 1000;
va_list += sizeof(int);
You're telling the compiler that you want it to consider va_list a pointer to an int (via the int * cast), then take the value (*) and add 1000 to it (+= 1000). Now advance the va_list pointer to the next argument on the stack.

Passing parameters dynamically to variadic functions

I was wondering if there was any way to pass parameters dynamically to variadic functions. i.e. If I have a function
int some_function (int a, int b, ...){/*blah*/}
and I am accepting a bunch of values from the user, I want some way of passing those values into the function:
some_function (a,b, val1,val2,...,valn)
I don't want to write different versions of all these functions, but I suspect there is no other option?
Variadic functions use a calling convention where the caller is responsible for popping the function parameters from the stack, so yes, it is possible to do this dynamically. It's not standardized in C, and normally would require some assembly to manually push the desired parameters, and invoke the variadic function correctly.
The cdecl calling convention requires that the arguments be pushed in the correct order, and after the call, the bytes pushed as arguments before the call are popped. In this way, the called function can receive an arbitrary number of parameters, as the caller will handle reverting the stack pointer to it's pre-call state. The space occupied by the arguments before the ... is the safe lower bound for number of bytes pushed. Additional variadic arguments are interpreted at runtime.
FFCALL is a library which provides wrappers for passing parameters dynamically to variadic functions. The group of functions you're interested in is avcall. Here's an example calling the functions you gave above:
#include <avcall.h>
av_alist argList;
int retVal;
av_start_int(argList, some_function, retval);
av_int(argList, a);
av_int(argList, b);
av_type(argList, val1);
...
av_type(argList, valn);
av_call(argList);
You might also find this link discussing generating wrappers around variadic functions in C, to be of interest in justifying why this isn't part of standard C.
A standard approach is to have each variadic function accompanied by a va_list-taking counterpart (as in printf and vprintf). The variadic version just converts ... to a va_list (using macros from stdarg.h) and calls its va_list-taking sister, which does actual work.
It might be interesting to try just passing an array, and then use the vararg macros anyway. Depending on stack alignment, it might Just Work (tm).
This is probably not an optimal solution, I mainly posted it because I found the idea interesting.
After trying it out, this approach worked on my linux x86, but not on x86-64 - it can probably be improved. This method will depend on stack alignment, struct alignment and probably more.
void varprint(int count, ...)
{
va_list ap;
int32_t i;
va_start(ap, count);
while(count-- ) {
i = va_arg(ap, int32_t);
printf("Argument: %d\n", i);
}
va_end(ap);
}
struct intstack
{
int32_t pos[99];
};
int main(int argc, char** argv)
{
struct intstack *args = malloc(sizeof(struct intstack));
args->pos[0] = 1;
args->pos[1] = 2;
args->pos[2] = 3;
args->pos[3] = 4;
args->pos[4] = 5;
varprint(5, *args);
return 0;
}
Depending on what it is you're passing around, it could be a discriminated union you're after here (as hinted at in the comments). That would avoid the need for variadic functions or arrays of void*, and answers the question "how does some_function know what you actually passed it". You might have code something like this:
enum thing_code { INTEGER, DOUBLE, LONG };
struct thing
{
enum thing_code code;
union
{
int a;
double b;
long c;
};
};
void some_function(size_t n_things, struct thing *things)
{
/* ... for each thing ... */
switch(things[i].code)
{
case INTEGER:
/* ... */
}
}
You can take this a step further and avoid the switch by replacing the code with one or more pointers to functions that do something useful with each thing. For example, if what you wanted to do was to simply print out each thing, you could have this:
struct thing
{
void (*print)(struct thing*);
union
{
...
};
}
void some_function(size_t n_things, struct thing *things)
{
/* .. for each thing .. */
things[i]->print(things[i]);
/* ... */
}

Resources