Christopher said:
Do variadic functions (such as printf()) always scan the format string
for format specifiers, even when there are no additional arguments?
If it is instead a QoI issue, what would be true for a typical
implementation?
Basically, I'm wondering whether there is any advantage to using
puts() instead of printf() for output of a string.
K&R2, section 7.7, page 156,
shows a function definition for minprintf().
It should give you some idea of the logic invlolved.
The logic of puts is relatively simple.
In my toy library, I have put_s like this:
#include <stdio.h>
#define put_c(c, stream) (putc((c), (stream)))
#define put_char(c) (put_c((c), stdout))
int put_s(const char *s)
{
while (*s != '\0') {
if (put_char(*s) == EOF && ferror(stdout) != 0) {
return EOF;
}
++s;
}
return put_char('\n');
}
My min_printf is like this:
#include <stdarg.h>
#define fsput_char(c) \
(put_char(c) == EOF && ferror(stdout) != 0 ? EOF : 1)
static int fsput_s(const char *);
static int fsput_u(unsigned);
static int fsput_u_plus_1(unsigned);
static int fsput_d(int);
int min_printf(const char *s, ...)
{
int count, increment;
va_list ap;
va_start(ap, s);
for (count = 0; *s != '\0'; ++s) {
if (*s == '%') {
switch (*++s) {
case 'c':
increment = fsput_char(va_arg(ap, int));
break;
case 'd':
increment = fsput_d(va_arg(ap, int));
break;
case 's':
increment = fsput_s(va_arg(ap, char *));
break;
case 'u':
increment = fsput_u(va_arg(ap, unsigned));
break;
default:
increment = fsput_char(*s);
break;
}
} else {
increment = fsput_char(*s);
}
if (increment != EOF) {
count += increment;
} else {
count = EOF;
break;
}
}
va_end(ap);
return count;
}
static int fsput_s(const char *s)
{
int count;
for (count = 0; *s != '\0'; ++s) {
if (put_char(*s) == EOF && ferror(stdout) != 0) {
return EOF;
}
++count;
}
return count;
}
static int fsput_u(unsigned integer)
{
int count;
unsigned digit, tenth;
tenth = integer / 10;
digit = integer - 10 * tenth + '0';
count = tenth != 0 ? fsput_u(tenth) : 0;
return count != EOF && put_char(digit) != EOF ? count + 1 : EOF;
}
static int fsput_u_plus_1(unsigned integer)
{
int count;
unsigned digit, tenth;
tenth = integer / 10;
digit = integer - 10 * tenth + '0';
if (digit == '9') {
if (tenth != 0) {
count = fsput_u_plus_1(tenth);
} else {
count = put_char('1') == EOF ? EOF : 1;
}
digit = '0';
} else {
count = tenth != 0 ? fsput_u(tenth) : 0;
++digit;
}
return count != EOF && put_char(digit) != EOF ? count + 1 : EOF;
}
static int fsput_d(int integer)
{
int count;
if (0 > integer) {
if (put_char('-') == EOF) {
return EOF;
}
count = fsput_u_plus_1(-(integer + 1));
return count != EOF ? count + 1 : EOF;
} else {
return fsput_u(integer);
}
}