Search code examples
cprintfvariadic-functions

va_args in c from <stdarg.h> does not work correctly


I am trying to write my own printf function in c, but I faced with a problem, when I want to call my functions with this arguments :

ft_printf ("Characters: %c %c\n",'s','e');

instead of getting 's' 'e' , I got 's' 's'. It looks like it does not go through all arguments,

this is my function :

    static int get_args(va_list args, char format)
    {
  if(format == 'c')
      return(print_char(va_arg(args,int))); //here I called va_args to retrieve args
    }
   

 int    ft_printf(const char *format, ...)
    {
        va_list args;
        int i;
        int len;
        
        len = 0;
        i = 0;
        
        va_start(args,format);
        while (format[i])
        {
            if (format[i] == '%')
            {
                      len += get_args(args, format[i + 1]);
                i++;
            }
            else
            {
                      write(1,&format[i],1);
                      len++;
                }
            i++;
        }
        va_end(args);
        return len;
    
    }

int main()
{
    printf ("Characters: %c %c \n",'s','e');
    ft_printf ("Characters: %c %c\n",'s','e');
    
    return 0;
}

Solution

  • After passing args to get_args() and calling va_arg inside, the value of the original args in ft_printf() is indeterminate†, and you can only va_end it.

    However, if you pass it by reference (with a pointer), it properly updates args in the original function:

    static int get_args(va_list *args, char format)
    {
      if (format == 'c')
          // here I called va_args to retrieve args
          return print_char(va_arg(*args, int));
    }
    
    
    int ft_printf(const char *format, ...)
    {
        // ...
        len += get_args(&args, format[i + 1]);
        // ...
    }
    

    † On some platforms, va_list is a type like an integer or pointer, so get_args receives a copy and va_arg can't update the original. On other platforms, it's an array type, so the function parameter becomes a pointer so it's automatically passed "by reference" and the original value is updated. You appear to be using a platform with the former type, where args in ft_printf isn't modified.