Reputation: 2887
I am asking this question to understand the working of printf as a function which is accepting variable length arguments.
I am learning the variable number of argument concept from here and what confused me is the datatype passing in va_arg(va_list,datatype). I mean they are mentioning one data type here. What about the case where we need to pass arguments with different datatypes. The same thing is done in printf function.
How exactly printf figures out the different type of argument types. As per my thinking they must be checking every % symbol in the first const char* argument and after that the token checking for particular datatypes.
Upvotes: 1
Views: 783
Reputation: 3870
The Following Variable argument list function explains you how the printf
will work.
#include <stdio.h>
#include <stdarg.h>
void foo(char *fmt, ...) // This Function works like same as printf
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
main()
{
// call the foo function here
// like foo("%d%s%c",3,"hai",'a');
}
For more reference see the man page of va_arg
It won't support char
and float
values, so we need to typecast it.
For float
you need to typecast the double
values.
Upvotes: 2
Reputation: 2096
printf
is a function, not a macro. It is defined as
int printf(const char *, ...)
and has variable number of arguments.
printf
use string to define number of arguments passed. Each % is used to move towards the stack and retrieve arguments.
So, if you passed
"%d %d %d", 1, 2
then 1, 2, and arbitrary value would be displayed. That is bad: you can walk down the stack using this function.
When passed
"%d %d", 1, 2, 3
then 1 and 2 would be displayed. And behaviour is undefined: usually __cdecl calling convention is used, so stack wouldn't be corrupted because cleaned by caller.
Upvotes: 1
Reputation: 1
Look into the source code of printf
in some free software standard C library implementation, e.g. GNU libc or musl-libc. I find musl-libc
very readable, look inside src/stdio/printf.c then src/stdio/vfprintf.c (where the real work is done). Of course it uses va_arg
according to the format control string (see stdarg(3). Notice that va_arg
is implemented inside the compiler, thru __builtin_va_arg
in GCC) . GCC also has builtin support for printf
Upvotes: 0
Reputation: 23500
Yes it checks the %X to see what data type or flags to use. Without this, it cannot know. The only way is if you use C++'s variadic templates. Other than that, C does it like below..
This example uses fwrite
to write the data to stdout
.
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
void C_Printf(const char *fmt, ...)
{
int fmtLength = strlen(fmt);
va_list VariableArgs;
va_start(VariableArgs, fmt);
for (int I = 0; I < fmtLength; I++)
{
if (fmt[I] == '%')
{
switch(tolower(fmt[++I]))
{
case 'f':
{
double d = va_arg(VariableArgs, double);
fwrite(&d, sizeof(double), 1, stdout);
}
break;
case 'i':
case 'd':
{
int i = va_arg(VariableArgs, int);
fwrite(&i, sizeof(int), 1, stdout);
}
break;
case 's':
{
const char *str = va_arg(VariableArgs, const char *);
fwrite(&str[0], sizeof(char), strlen(str), stdout);
}
break;
default:
break;
}
}
else
fwrite(&fmt[I], sizeof(char), 1, stdout);
}
va_end(VariableArgs);
}
int main()
{
C_Printf("%s", "hello there");
}
Upvotes: 0