Implement printf and sprintf using Linux kernel variable parameters in C Language

Source: Internet
Author: User
Tags define null

Implement printf and sprintf using Linux kernel variable parameters in C Language

Yesterday, I published an fprintf function implemented using a variable parameter. In fact, it is not completely implemented using a variable parameter, because a pointer like FILE * needs to contain stdio. h. This header file can be used to implement this function. Today, let's take a look at how to discard stdio. h. All 0 starts to implement printf and sprintf. Of course, this code was obtained in the Linux kernel and modified and transplanted by myself, in the DevC ++ compiling environment, it passes the test. Let's look at the Code:

#include
#define NULL 0
// If the string is a number, return the number
static int skip_atoi (const char ** s)
{
int i = 0;

while (isdigit (** s))
i = i * 10 + * ((* s) ++)-'0';
return i;
}

static inline int isdigit (int ch)
{
return (ch> = '0') && (ch <= '9'); // Return the number from 0-9 to the character
}

#define ZEROPAD 1 / * pad with zero * /
#define SIGN 2 / * unsigned / signed long * /
#define PLUS 4 / * show plus * /
#define SPACE 8 / * space if plus * /
#define LEFT 16 / * left justified * /
#define SMALL 32 / * Must be 32 == 0x20 * /
#define SPECIAL 64 / * 0x * /

// This macro is mainly used to implement the determination of what base number to convert
#define __do_div (n, base) ({\
int __res; \
__res = ((unsigned long) n)% (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res;})

static char * number (char * str, long num, int base, int size, int precision,
int type)
{
/ * This string array stores 16 digits 0-15, which will be used for base conversion * /
static const char digits [16] = "0123456789ABCDEF";

char tmp [66];
char c, sign, locase;
int i;

/ * locase = 0 or 0x20, produces the same number or letter as the case, maybe the letters are lowercase * /
locase = (type & SMALL);
if (type & LEFT)
type & = ~ ZEROPAD;
if (base <2 || base> 36)
return NULL;
c = (type & ZEROPAD)? '0': '';
sign = 0;
if (type & SIGN) {
if (num <0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = '';
size--;
}
}
// Detect the base number, whether it is binary or octal or hexadecimal
if (type & SPECIAL) {
if (base == 16)
size-= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp [i ++] = '0';
else
while (num! = 0)
tmp [i ++] = (digits [__ do_div (num, base)] | locase);
if (i> precision)
precision = i;
size-= precision;
if (! (type & (ZEROPAD + LEFT)))
while (size-> 0)
* str ++ = '';
if (sign)
* str ++ = sign;
if (type & SPECIAL) {
if (base == 8)
* str ++ = '0';
else if (base == 16) {
* str ++ = '0';
* str ++ = ('X' | locase);
}
}
if (! (type & LEFT))
while (size-> 0)
* str ++ = c;
while (i <precision--)
* str ++ = '0';
while (i--> 0)
* str ++ = tmp [i];
while (size-> 0)
* str ++ = '';
return str;
}

int vsprintf (char * buf, const char * fmt, va_list args)
{
int len;
unsigned long num;
int i, base;
char * str;
const char * s;
int flags;
int field_width; / * Bit width output * /
int precision;
int qualifier;
// Judge here, if the% symbol does not exist in the string fmt, the string continues to traverse backward
for (str = buf; * fmt; ++ fmt) {
if (* fmt! = '%') {
* str ++ = * fmt;
continue;
}

// The program sets the flag
flags = 0;
repeat:
++ fmt; / * this also skips first '%' * /
// format control
switch (* fmt) {
case '-':
flags | = LEFT;
goto repeat;
case '+':
flags | = PLUS;
goto repeat;
case '':
flags | = SPACE;
goto repeat;
case '#':
flags | = SPECIAL;
goto repeat;
case '0':
flags | = ZEROPAD;
goto repeat;
}

// Get the width, here is mainly to implement the bit width mechanism of printf
field_width = -1;
if (isdigit (* fmt))
field_width = skip_atoi (& fmt);
else if (* fmt == '*') {
++ fmt;
field_width = va_arg (args, int);
if (field_width <0) {
field_width = -field_width;
flags | = LEFT;
}
}

precision = -1;
if (* fmt == '.') {
++ fmt;
if (isdigit (* fmt))
precision = skip_atoi (& fmt);
else if (* fmt == '*') {
++ fmt;
precision = va_arg (args, int);
}
if (precision <0)
precision = 0;
}

/ * The resulting conversion qualifier * /
qualifier = -1;
if (* fmt == 'h' || * fmt == 'l' || * fmt == 'L') {
qualifier = * fmt;
++ fmt;
}

/ * The default base is decimal * /
base = 10;
// The following is mainly to achieve printf format output. For example:% d,% c,% u ... etc.
switch (* fmt) {
case 'c': // Output as characters
if (! (flags & LEFT))
while (--field_width> 0)
* str ++ = '';
* str ++ = (unsigned char) va_arg (args, int);
while (--field_width> 0)
* str ++ = '';
continue;

case 's': // Output as a string
s = va_arg (args, char *);
len = strnlen (s, precision);

if (! (flags & LEFT))
while (len <field_width--)
* str ++ = '';
for (i = 0; i <len; ++ i)
* str ++ = * s ++;
while (len <field_width--)
* str ++ = '';
continue;

case 'p': // Output as an address
if (field_width == -1) {
field_width = 2 * sizeof (void *);
flags | = ZEROPAD;
}
str = number (str,
(unsigned long) va_arg (args, void *), 16,
field_width, precision, flags);
continue;

case 'n':
if (qualifier == 'l') {
long * ip = va_arg (args, long *);
* ip = (str-buf);
} else {
int * ip = va_arg (args, int *);
* ip = (str-buf);
}
continue;

case '%': // This indicates that the character% is present in the string
* str ++ = '%';
continue;

/ * integer number formats-set up the flags and "break" * /
case 'o': //% o means octal output
base = 8;
break;

case 'x': //% x or% X means hexadecimal output
flags | = SMALL;
case 'X':
base = 16;
break;

case 'd': //% d% i integer output,% u unsigned integer
case 'i':
flags | = SIGN;
case 'u':
break;

default:
* str ++ = '%';
if (* fmt)
* str ++ = * fmt;
else
--fmt;
continue;
}
if (qualifier == 'l') // Output as unsigned long
num = va_arg (args, unsigned long);
else if (qualifier == 'h') {
num = (unsigned short) va_arg (args, int);
if (flags & SIGN)
num = (short) num;
} else if (flags & SIGN)
num = va_arg (args, int);
else
num = va_arg (args, unsigned int);
str = number (str, num, base, field_width, precision, flags);
}
* str = '\ 0'; // String traversal stops when there is \ 0
return str-buf;
}
// variable parameter form to implement sprintf
int mysprintf (char * buf, const char * fmt, ...)
{
va_list args;
int i;
va_start (args, fmt);
// Write the obtained fmt format string to the buf cache
i = vsprintf (buf, fmt, args);
// Release args
va_end (args);
return i;
}

// Variable parameter implementation for myprintf
int myprintf (const char * fmt, ...)
{
char printf_buf [1024];
va_list args;
int printed;
va_start (args, fmt);
printed = vsprintf (printf_buf, fmt, args);
va_end (args);
puts (printf_buf);
return printed;
}

int main (void)
{
myprintf ("Output string: hello world! \ n");
static int sum, a = 3, b = 4;
sum = a + b;
myprintf ("sum (decimal output):% d \ n", sum);
myprintf ("sum (hexadecimal output):% p \ n", sum);
char buffer [128] = {0};
// Save the string in an array buffer
mysprintf (buffer, "Output string: hello world! \ n");
// Output the contents of this buffer in string format
myprintf ("buffer:% s \ n", buffer);
return 0;
}
Running result:

 

After reading the code, we can see that our program does not contain the stdio. h header file, which implements the printf and sprintf functions. In this case, if you want to implement a printf function by yourself, the code can be called as a file. Haha!



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.