c - 格式化打印显示意外结果

标签 c printf string-formatting

我正在尝试创建一个格式化的打印功能并遇到这个我不知道是什么原因的问题

想法

using the power of va_list, i create a function pf() inside this function there's a for loop that i used to navigate cross the string _Str just after entering the for loop there's a while that test's on (*conversion) and '%' to print characters until meet the first '%', is meted there's a switch to handle the arguments

代码:

主.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;
}

基础.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 参数时。上面的代码工作正常并且符合预期

Using arguments

Compiling

[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");

not using arguments(unexpected result)

Compiling

[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] $

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

最佳答案

您的内部 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); 
}

关于c - 格式化打印显示意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35779893/

相关文章:

c - 如何在 fprintf 中使用 Variadic 宏

c - 如何在 C 中打印 errno 的符号名称?

c - 在一个函数中打印的值工作正常,但在下一个函数中打印的值是错误的(返回 0.00)

python - 如何防止 PyMySQL 转义标识符名称?

Python - 从字典项创建字符串(用于写入 postgresql 数据库)

在不支持 double 的 C 编译器上将 64 位 double float 据转换为 Uint32

c - 查找\r在c中的位置

c - pthread 并在 C 中递归调用 execvp

wpf - wpf中的字符串格式

c - 如何访问动态分配的结构数组中的项?