格式化打印显示意外结果

时间:2016-03-03 18:16:17

标签: c printf string-formatting

我试图创建一个格式化的打印功能并面对这个我不知道其原因的问题

想法

  

使用 va_list 的强大功能,我创建了一个函数 pf()   在这个函数里面有一个 for 循环,用于在输入 for 循环之后导航越过字符串 _Str ' sa while 测试(*转化)和'%' 打印字符,直到遇到第一个&#39 ;%' ,在那里' 开关来处理参数

代码:

的main.c

#include "base.h"

void pf(char* _Str, ...) 
{ 
    char* conversion; 
    //
    u_int i; 
    char* S; 

    //Initializing arguments 
    //
    va_list arg; 
    va_start(arg, _Str); 

    for(conversion = _Str; *conversion != '\0'; conversion++) 
    { 
        while( *conversion != '%' ) 
        { 
            putchar(*conversion);
            conversion++; 
        }//end while
        conversion++; 
        //arguments
        //
        switch(*conversion) 
        {   
            case 'c' : i = va_arg(arg, int);        //char argument
                        putchar(i);
                        break; 
            case 'd' : i = va_arg(arg, int);        //Decimal/Integer argument
                        if(i < 0) { i = -i; putchar('-');} 
                        puts(convert(i, 10));
                        break; 
            case 'o': i = va_arg(arg,u_int); //Octal representation
                        puts(convert(i, 8));
                        break; 
            case 's': S = va_arg(arg, char *);      //string argument
                        puts(S); 
                        break; 
            case 'x': i = va_arg(arg, u_int); //Hexadecimal representation
                        puts(convert(i, 16));
                        break; 
        }//end switch   
    }//end for
    //
    //
    va_end(arg); 
}// end pf()
int main(int argc, char** argv)
{
    pf("test1\vtest2 %d %o %x %c%c",10,512,1024,'O','K'); 
    return 0;
}

base.h

#ifndef BASE_H_
 #define BASE_H_
  #ifndef EOF // (EOF) - End Of File character. (-1)
   #define EOF (-1)
   #endif// EOF 
 #include<stdio.h>
 #include<stdlib.h>


 #include<stdarg.h> 
  typedef unsigned int u_int;

    void pf(char*, ...);            //  Our printf function
    char* convert(u_int, int);      // Convert integer number into octal, hex, etc.
#endif // BASE_H_

问题

pf 提供参数时。上面的代码可以正常工作并且符合预期

  

使用参数

     

编译

[ar.lnx@host printf] $ make
Building objects..
gcc -c -o main.o main.c -I. -Wall 
Building the application core..
gcc -o x main.o -I. -g
Finish.
[ar.lnx@host printf] $ ./x
test1
     test2 10
 1000
 400
 OK[ar.lnx@host printf]

但是当不对 pf 提出任何论据时,它会显示出意想不到的结果! 例如尝试测试

pf("test3\vtest4");
  

不使用参数(意外结果)

     

编译

[ar.lnx@host printf] $ make
Building objects..
gcc -c -o main.o main.c -I. -Wall 
Building the application core..
gcc -o x main.o base.o  -I. -g
Finish.
[ar.lnx@host printf] $ ./x
test3
     test4 �@�@@@@@@@@@@@\@@@@�@@@@@���������h�����
                                                   ��������X��� ����@ ����zRx
                                                                            ����*zRx
                                                                                   $���PF▒J
                                                                                           �?▒;*3$"D���
[ar.lnx@host printf] $

我不知道该程序是如何显示这些结果的,有人帮我理解了

1 个答案:

答案 0 :(得分:3)

您的内部while循环未检查空终止符,因此它可以循环遍历_Str的末尾到周围的内存中。如果_Str的末尾不存在格式说明符,则代码将失败(在您的示例中,您的失败字符串中根本没有任何%个字符)。所以while循环不会中断,除非发生在字符串之外的内存中遇到%。在那之前,它只是打印出周围内存的字节,这是你在输出中看到的。

请改为尝试:

void pf(char* _Str, ...) 
{ 
    char* conversion; 
    //
    int i; 
    u_int ui; 
    char* S; 

    //Initializing arguments 
    //
    va_list arg; 
    va_start(arg, _Str); 

    for(conversion = _Str; *conversion != '\0'; conversion++) 
    { 
        while( (*conversion != '%') && (*conversion != '\0') ) 
        { 
            putchar(*conversion);
            conversion++; 
        }//end while

        if (*conversion == '\0') 
            break;

        conversion++;  // skip '%'

        //arguments
        //
        switch (*conversion) 
        {   
            case 'c' : i = va_arg(arg, int); //char argument
                        putchar(i);
                        break; 
            case 'd' : i = va_arg(arg, int); //Decimal/Integer argument
                        if (i < 0) { i = -i; putchar('-');} 
                        puts(convert(i, 10));
                        break; 
            case 'o': ui = va_arg(arg, u_int); //Octal representation
                        puts(convert(ui, 8));
                        break; 
            case 's': S = va_arg(arg, char *); //string argument
                        puts(S); 
                        break; 
            case 'x': ui = va_arg(arg, u_int); //Hexadecimal representation
                        puts(convert(ui, 16));
                        break; 
            case '%': putchar('%'); //percent literal
                        break; 
            default : putchar('%'); // anything else
                        putchar(*conversion);
                        break; 
        }//end switch   
    }//end for

    va_end(arg); 
}// end pf()

话虽如此,在此示例中无需手动实现格式化输出(特别是因为您没有实现格式化支持的所有选项)。你应该使用vprintf(),让它为你付出艰苦的努力,例如:

void pf(char* _Str, ...) 
{ 
    va_list arg; 
    va_start(arg, _Str); 
    vprintf(_Str, arg);​
    va_end(arg); 
}