Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call a vararg function with an array?

Tags:

arrays

c

In this example below, I would like to pass to a function that receive variable number of arguments the content of an array.

In other terms, I would like to pass to printf the content of foo by value and thus, pass these arguments on the stack.

#include <stdarg.h>
#include <stdio.h>

void main()
{
    int foo[] = {1,2,3,4};

    printf("%d, %d, %d, %d\n", foo);
}

I know this example looks stupid because I can use printf("%d, %d, %d, %d\n", 1,2,3,4);. Just imagine I'm calling void bar(char** a, ...) instead and the array is something I receive from RS232...

EDIT

In other words, I would like to avoid this:

#include <stdarg.h>
#include <stdio.h>

void main()
{
    int foo[] = {1,2,3,4};

    switch(sizeof(foo))
    {
       case 1: printf("%d, %d, %d, %d\n", foo[0]); break;
       case 2: printf("%d, %d, %d, %d\n", foo[0], foo[1]); break;
       case 3: printf("%d, %d, %d, %d\n", foo[0], foo[1], foo[2]); break;
       case 4: printf("%d, %d, %d, %d\n", foo[0], foo[1], foo[2], foo[3]); break;
       ...
    }
}
like image 640
nowox Avatar asked Apr 11 '16 12:04

nowox


2 Answers

I would like to pass to printf the content of foo by value and thus, pass these arguments on the stack.

You cannot pass an array by value. Not by "normal" function call, and not by varargs either (which is, basically, just a different way of reading the stack).

Whenever you use an array as argument to a function, what the called function receives is a pointer.

The easiest example for this is the char array, a.k.a. "string".

int main()
{
    char buffer1[100];
    char buffer2[] = "Hello";
    strcpy( buffer2, buffer1 );
}

What strcpy() "sees" is not two arrays, but two pointers:

char * strcpy( char * restrict s1, const char * restrict s2 )
{
    // Yes I know this is a naive implementation in more than one way.
    char * rc = s1;
    while ( ( *s1++ = *s2++ ) );
    return rc;
}

(This is why the size of the array is only known in the scope the array was declared in. Once you pass it around, it's just a pointer, with no place to put the size information.)

The same holds true for passing an array to a varargs function: What ends up on the stack is a pointer to the (first element of) the array, not the whole array.

You can pass an array by reference and do useful things with it in the called function if:

  1. you pass the (pointer to the) array and a count of elements (think argc / argv), or
  2. caller and callee agree on a fixed size, or
  3. caller and callee agree on the array being "terminated" in some way.

Standard printf() does the last one for "%s" and strings (which are terminated by '\0'), but is not equipped to do so with, as in your example, an int[] array. So you would have to write your own custom printme().

In no case are you passing the array "by value". If you think about it, it wouldn't make much sense to copy all elements to the stack for larger arrays anyway.

like image 79
DevSolar Avatar answered Oct 02 '22 00:10

DevSolar


Short answer: No, you can't do it, it's impossible.

Slightly longer answer: Well, maybe you can do it, but it's super tricky. You are basically trying to call a function with an argument list that is not known until run time. There are libraries that can help you dynamically construct argument lists and call functions with them; one library is libffi: https://sourceware.org/libffi/.

See also question 15.13 in the C FAQ list: How can I call a function with an argument list built up at run time?

See also these previous Stackoverflow questions:
C late binding with unknown arguments
How to call functions by their pointers passing multiple arguments in C?
Calling a variadic function with an unknown number of parameters

like image 23
Steve Summit Avatar answered Oct 02 '22 00:10

Steve Summit