Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the following va_arg macro work?

I am reading a stdarg.h (link below) header file which defines the va_arg macro as follows

/*
 * Increment ap to the next argument in the list while returing a
 * pointer to what ap pointed to first, which is of type t.
 *
 * We cast to void* and then to t* because this avoids a warning about
 * increasing the alignment requirement.
 */
#define va_arg(ap, t)                   \
 (((ap) = (ap) + __va_argsiz(t)),       \
  *((t*) (void*) ((ap) - __va_argsiz(t))))

The line

((ap) = (ap) + __va_argsiz(t))

reassigns the value of ap however I don't understand the purpose of the comma or the line

*((t*) (void*) ((ap) - __va_argsiz(t)))

Link to stdarg.h file

like image 389
duper21 Avatar asked Aug 31 '25 22:08

duper21


2 Answers

We need to return to the caller what ap has been pointed to, and advance ap. An equivalent would be

    old_ap = ap
    ap = ap + argsiz
    return *old_ap

However, that would require an extra variable, which is very hard (if possible) deal with in a macro in a portable way. Instead, the macro relies on a comma expression. It advances ap, and then computes its old value, which becomes a value of the comma expression, that is of the entire macro.

like image 151
user58697 Avatar answered Sep 03 '25 18:09

user58697


There is an expression with the comma operator.

The first sub-expression

(((ap) = (ap) + __va_argsiz(t))

increase the pointer ap.

The second sub-expression

*((t*) (void*) ((ap) - __va_argsiz(t))))

returns the value pointed to by the pointer ap before its increment.

If you have a question relative to the comma operator then it allows to combine several full expressions in one expression.

Consider for example the following program

#include <stdio.h>

int main(void) 
{
    int a[] = { 1, 2 };

    size_t i = 0;

    printf( "%d\n", ( i++, a[i] ) );

    return 0;
}

Its output is

2

Here the argument of the printf call is an expression with the comma operator.

Or a more interesting example

#include <stdio.h>

int main(void) 
{
    int a[] = { 1, 2 };

    size_t i = 0;

    printf( "%d\n", a[i] ), i++, printf( "%d\n", a[i] );

    return 0;
}

The program output is

1
2

Here the expression statement

    printf( "%d\n", a[i] ), i++, printf( "%d\n", a[i] );

contains an expression with using two comma operators.

like image 34
Vlad from Moscow Avatar answered Sep 03 '25 17:09

Vlad from Moscow