0

I'm trying to do a naive implementation of the C-standard function printf. So far I've just written some testing code to help me better understand the use of variable arguments lists. However, I don't know why my output contains an extra line.

Here is my code:

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

void    print_test_helper(char *string, va_list args)
{
    while (*string)
    {
        if (*string == '%')
        {
            string = string + 2; //increment pointer by two spots to "\n"
            printf("%s", (va_arg(args, char*)));
        }
        else
        {
            write(1, &*string, 1);
            string++;
        }
    }
}


void    print_test(char *string, ...)
{
    va_list ap;
    va_start(ap, string);
    print_test_helper(string, ap);
}

int main()
{
    print_test("this is a %s\n", "string");
    return 0;
}

The way I see it, my print_test_helper should keep writing the string passed to it up until it sees the '%' character, after which it skips two spots to the newline character. The function then calls the printf method to simply printout the argument held in the list, but the output is like so:

this is a                                                                                                               
string

As you can see, it contains a new line. Any ideas why?

Edit:

changing the line printf("%s", va_arg(args, char*)) to write(1, va_arg(args, char*), 6); produces the expected behavior. Is this an issue with the interaction between write and printf?

Edit 2:

See the answer below!

Thunderpurtz
  • 123
  • 1
  • 9
  • Look carefully at the order you're doing things in. A debugger would likely help a lot. – Retired Ninja Apr 30 '19 at 04:22
  • 3
    It's not a good idea to mix `printf` and `write` (would be better to either use Standard C I/O for all cases, or use POSIX I/O for all cases, e.g. use `putchar` instead of `write`). The Standard C I/O may do its own output buffering. – M.M Apr 30 '19 at 04:23
  • 1
    When the `%` is encountered, adding `2` means `string` points at the newline character. You need to add `3`. Also `&*string` and `string` are equivalent. – Peter Apr 30 '19 at 04:24
  • @Peter I think it is intentional to point at the newline. (But that piece of code has another issue that if the string ends in `%` it will read off the end indefinitely) – M.M Apr 30 '19 at 04:25
  • 1
    Side note, `write()` system call is not a buffered IO while library function `printf()` is buffered. – Achal Apr 30 '19 at 04:32
  • @RetiredNinja i think i'm just dumb, but i can't really see what's going on with the debugger either... Everything says to me that the pointer gets moved, then the printf call happens. – Thunderpurtz Apr 30 '19 at 04:49
  • @M.M yes its supposed to print a newline, it's not a fully built function, mostly just testing how to use variable arguments, but the output is bugging me. – Thunderpurtz Apr 30 '19 at 04:50
  • Have you tried using putchar instead of write? – M.M Apr 30 '19 at 04:51
  • @M.M switching from printf to write produces the expected behavior. I used write since putchar would need to be done in a loop. changed printf("%s", va_arg(args, char*); to write(1, va_arg(args, char*), 6); – Thunderpurtz Apr 30 '19 at 04:56
  • @Achal I think the buffering might be the cause of the problem. When I initiate a fflush(stdout) after the printf call, the proper output is given. I don't really understand the buffering though. – Thunderpurtz Apr 30 '19 at 05:00
  • The standard C I/O might buffer the whole line whereas write doesn't, so the `write` of `\n` occurs before the standard C buffer is flushed (which is actually never, since you never output a newline that way) – M.M Apr 30 '19 at 05:10
  • yep @M.M, check my answer, I'm pretty sure that's exactly it. – Thunderpurtz Apr 30 '19 at 05:11

1 Answers1

0

@Achal pointed me in the right direction about buffering in the printf. As far as I can tell according to this stack overflow post, printf isn't guaranteed to print to the console unless a few conditions are met. A few of those namely being an fflush, a program exit, or a newline.

In my case, the function was writing out every character to the stdout (write is not buffered) and when it encountered the "%s\n", printf was doing its job, only it was buffered. So my assumption is that when "\n" gets written to the stdout, printf realizes it needs to dump its buffer and it does so, only after write puts down the newline.

As mentioned by @M.M it's not a good idea to mix write and printf and I guess this post is testament to that. I didn't intend to end up with it like that though, I was simply using printf for testing since I was lazy, but I ended up learning more about how it works. Cheers.

Thunderpurtz
  • 123
  • 1
  • 9