Library I/O Functions in Unix/Linux – Programming Project: Printf-like Function

The programming project is to write a printf()-like function for formatted printing of chars, strings, unsigned integers, signed integers in decimal and unsigned integers in HEX. The objective of the programming project is to let the reader understand how library I/O functions are implemented. In the case of printf(), which can print a varying number of items of different types, the basic operation is to print a single char.

1. Project Specification

In Linux, putchar(char c) prints a char. Use only putchar() to implement a function

int myprintf(char *fmt, . . .)

for formatted printing of other parameters, where fmt is a format string containing

%c  : print  char

%s  : print  string

%u  : print  unsigned integer

%d  : print  signed integer

%x  : print  unsigned integer in HEX

For simplicity, we shall ignore field width and precision. Just print the parameters, if any, as specified in the format string. Note that the number and type of the items to be printed are implicitly specified by the number of % symbols in the format string.

2. Base Code of Project

(1). The reader should implement a prints(char *s) function for printing strings.

(2). The following shows a printu() function, which prints unsigned integers in decimal.

char *ctable = “0123456789ABCDEF”;

int BASE = 10; // for printing numbers in decimal

int rpu(unsigned int x)

{

char c; if (x){

c = ctable[x % BASE];

rpu(x / BASE);

putchar(c);

}

}

int printu(unsigned int x)

{

(x==0)? putchar(‘0’) : rpu(x);

putchar(‘ ‘);

}

The function rpu(x) recursively generates the digits of x % 10 in ASCII and prints them on the return path. For example, if x=123, the digits are generated in the order of ‘3’, 2′, ‘1’, which are printed as ‘1’, ‘2’, ‘3’ as they should.

(3). With the printu() function, the reader should be able to implement a printd() function to print signed integers.

(4). Implement a printx() function to print unsigned integers in HEX (for addresses).

(5). Assume that we have printc(), prints(), printd(), printu() and printx() functions. Then implement myprintf(char *fmt, …) by the following algorithm.

3. Algorithm of myprintf()

Assume that the format string fmt = “char=%c string=%s integer=%d u32=%x\n”. It implies that there are 4 additional parameters of char, char *, int, unsigned int, types respectively. The algorithm of myprint() is as follows.

  1.  Scan the format string fmt. Print any char that’s not %. For each ‘\n’ char, print an extra ‘\r’char.
  2.  When encounter a ‘%’, get the next char, which must be one of ‘c’, ‘s’, ‘u’, ‘d’ or ‘x’. Use va_arg (ap, type) to extract the corresponding parameter. Then call the print function by the parameter type.
  3.  The algorithm ends when scanning the fmt string ends.

Exercise 9.6: Assume 32-bit GCC. Implement the myprintf(char *fmt,…) function by the following algorithm and explain WHY the algorithm works.

int myprintf(char *fmt, . . .)

{

char *cp = fmt;

int *ip = (int *)&fmt + 1;

// Use cp to scan the format string for %TYPE symbols;

// Use ip to access and print each item by TYPE;

}

4. Project Refinements

  1.  Define tab key as 8 spaces. Add %t to the format string for tab keys.
  2.  Modify %u, %d and %x to include a width field, e.g. %8d prints an integer in a space of 8 chars and right-justified, etc.

5. Project Demonstration and Sample Solutions

Demonstrate the myprintf() function by driver programs. Sample solution to the programming project is available at the book’s website for downloading. Source code of the project for instructors is available on request.

Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.

Leave a Reply

Your email address will not be published. Required fields are marked *