Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

stdarg and printf() in C

The <stdarg.h> header file is used to make functions accept undefined number of arguments, right?

So, the printf() funtion of <stdio.h> must be using <stdarg.h> to accept avariable number of arguments(please correct me if I'm mistaken).

I found the following lines in the stdio.h file of gcc:

#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# ifdef __GNUC__
#  ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list;
#   define _VA_LIST_DEFINED
#  endif
# else
#  include <stdarg.h>//////////////////////stdarg.h IS INCLUDED!///////////
# endif
#endif

I can't understand most of what's in it, but it appears to be including <stdarg.h>

So, if printf() uses <stdarg.h> for accepting variable number of arguments and stdio.h has printf(), a C program using printf() need not include <stdarg.h> does it?

I tried a program which had printf() and a user-defined function accepting variable number of arguments.

The program I tried is:

#include<stdio.h>
//#include<stdarg.h>///If this is included, the program works fine.

void fn(int num, ...)
{
    va_list vlist;
    va_start(vlist, num);//initialising va_start (predefined)

    int i;

    for(i=0; i<num; ++i)
    {
        printf("%d\n", va_arg(vlist, int));
    }

    va_end(vlist);//clean up memory
}

int main()
{
    fn(3, 18, 11, 12);
    printf("\n");
    fn(6, 18, 11, 32, 46, 01, 12);

    return 0;
}

It works fine if <stdarg.h> is included but otherwise generates the following error:

40484293.c:13:38: error: expected expression before ‘int’
         printf("%d\n", va_arg(vlist, int));//////error: expected expression before 'int'/////////
                                      ^~~

How is this?

Or is it that printf() doesn't use <stdarg.h> for accepting variable number of arguments? If so, how is it done?

like image 428
J...S Avatar asked Nov 08 '16 10:11

J...S


1 Answers

Consider:

stdio.h:

int my_printf(const char *s, ...); 

Do you need <stdarg.h>? No, you don't. ... is part of the grammar of the language - it's "built-in". However, as soon as you want to do anything meaningful and portable with such list of arguments, you need the names defined in there: va_list, va_start and so on.

stdio.c:

#include "stdio.h"
#include "stdarg.h"

int my_printf(const char *s, ...)
{
   va_list va;
   va_start(va, s);

   /* and so on */
}

But this will be necessary, essentially, in the implementation of your libc which is something you don't see unless you compile the library on your own. What you instead get is the libc shared library, which has already been compiled to machine code.

So, if printf() uses for accepting variable number of arguments and stdio.h has printf(), a C program using printf() need not include does it?

Even if it were so, you cannot rely on that, otherwise your code is ill-formed: you must include all the headers anyway if a name belonging to them is used, regardless whether the implementation already does that or not.

like image 105
edmz Avatar answered Sep 21 '22 17:09

edmz