I/O - printf.c

The printf() library function is unimplemented in the current version of the library sets in the ANSI libraries, but it is found in the terminal.c file.

This difference has been planned because often no terminal is available at all or a terminal depends highly on the user hardware.

The ANSI library contains several functions which makes it simple to implement the printf() function with all its special cases in a few lines.

The first, ANSI-compliant way is to allocate a buffer and then use the vsprintf() ANSI function .

Listing: An implementation of the printf() function


int printf(const char *format, ...) {   char outbuf[MAXLINE]; 
  int i; 
  va_list args; 
  va_start(args, format); 
  i = vsprintf(outbuf, format, args); 
  va_end(args); 
  WriteString(outbuf); 
  return i; 
} 

The value of MAXLINE defines the maximum size of any value of printf(). The WriteString() function is assumed to write one string to a terminal. There are two disadvantages to this solution:

Two non-ANSI functions, vprintf() and set_printf(), are provided in its newer library versions in order to avoid both disadvantages. Because these functions are a non-ANSI extension, they are not contained in the stdio.h header file. Therefore, their prototypes must be specified before they are used:

Listing: Prototypes of vprintf() and set_printf()


int vprintf(const char *pformat, va_list args); void set_printf(void (*f)(char)); 

The set_printf() function installs a callback function, which is called later for every character which should be printed by vprintf().

Be advised that the standard ANSI C printf() derivatives functions, sprintf() and vsprintf(), are also implemented by calls to set_printf() and vprintf(). This way much of the code for all printf derivatives can be shared across them.

There is also a limitation of the current implementation of printf(). Because the callback function is not passed as an argument to vprintf(), but held in a global variable, all the printf() derivatives are not reentrant. Even calls to different derivatives at the same time are not allowed.

For example, a simple implementation of a printf() with vprintf() and set_printf() is shown in the following listing:

Listing: Implementation of prinft() with vprintf() and set_printf()


int printf(const char *format, ...){   int i; 
  va_list args; 
  set_printf(PutChar); 
  va_start(args, format); 
  i = vprintf(format, args); 
  va_end(args); 
  return i; 
} 

The PutChar()function is assumed to print one character to the terminal.

Another remark has to be made about the printf() and scanf() functions. The full source code is provided of all printf() derivatives in "printf.c" and of scanf() in scanf.c. Usually many of the features of printf() and scanf() are not used by a specific application. The source code of the library modules printf and scanf contains switches (defines) to allow the use to switch off unused parts of the code. This especially includes the large floating-point parts of vprintf() and vsscanf().