Chinaunix首页 | 论坛 | 博客
  • 博客访问: 660212
  • 博文数量: 171
  • 博客积分: 2246
  • 博客等级: 大尉
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-31 11:45
文章分类

全部博文(171)

文章存档

2018年(3)

2017年(4)

2015年(1)

2014年(20)

2013年(57)

2012年(86)

分类: LINUX

2013-12-02 12:43:20

关于unix高级环境编程 编译时的err_sys和err_quit错误的解决办法

 其实在附录B中W. Richard Stevens, Stephen A. Rago已经实现了这些函数,把这些实现了的函数写成了头文件,再编译程序时只要包含该头文件就不会出现编译错误的情况了。
apueerror.h

  1.        #include <errno.h> /* for definition of errno */
  2.        #include <stdarg.h> /* ISO C variable aruments */
  3.        static void err_doit(int, int, const char *, va_list);
  4.        /*
  5.         * Nonfatal error related to a system call.
  6.         * Print a message and return.
  7.         */
  8.        void  err_ret(const char *fmt, ...)
  9.        {
  10.            va_list ap;
  11.            va_start(ap, fmt);
  12.            err_doit(1, errno, fmt, ap);
  13.            va_end(ap);
  14.        }
  15.        /*
  16.         * Fatal error related to a system call.
  17.         * Print a message and terminate.
  18.         */
  19.        void  err_sys(const char *fmt, ...)
  20.        {
  21.            va_list ap;
  22.            va_start(ap, fmt);
  23.            err_doit(1, errno, fmt, ap);
  24.            va_end(ap);
  25.            exit(1);
  26.        }
  27.        /*
  28.         * Fatal error unrelated to a system call.
  29.         * Error code passed as explict parameter.
  30.         * Print a message and terminate.
  31.         */
  32.        void  err_exit(int error, const char *fmt, ...)
  33.        {
  34.            va_list ap;
  35.            va_start(ap, fmt);
  36.            err_doit(1, error, fmt, ap);
  37.            va_end(ap);
  38.            exit(1);
  39.        }
  40.        /*
  41.         * Fatal error related to a system call.
  42.         * Print a message, dump core, and terminate.
  43.         */
  44.        void  err_dump(const char *fmt, ...)
  45.        {
  46.            va_list ap;
  47.            va_start(ap, fmt);
  48.            err_doit(1, errno, fmt, ap);
  49.            va_end(ap);
  50.            abort(); /* dump core and terminate */
  51.            exit(1); /* shouldn't get here */
  52.        }
  53.        /*
  54.         * Nonfatal error unrelated to a system call.
  55.         * Print a message and return.
  56.         */
  57.        void  err_msg(const char *fmt, ...)
  58.        {
  59.            va_list ap;
  60.            va_start(ap, fmt);
  61.            err_doit(0, 0, fmt, ap);
  62.            va_end(ap);
  63.        }
  64.        /*
  65.         * Fatal error unrelated to a system call.
  66.         * Print a message and terminate.
  67.         */
  68.        void  err_quit(const char *fmt, ...)
  69.        {
  70.            va_list ap;
  71.            va_start(ap, fmt);
  72.            err_doit(0, 0, fmt, ap);
  73.            va_end(ap);
  74.            exit(1);
  75.        }
  76.        /*
  77.         * Print a message and return to caller.
  78.         * Caller specifies "errnoflag".
  79.         */
  80.        static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
  81.        {
  82.           char buf[MAXLINE];
  83.           vsnprintf(buf, MAXLINE, fmt, ap);
  84.           if (errnoflag)
  85.               snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",strerror(error));
  86.           strcat(buf, "\n");
  87.           fflush(stdout); /* in case stdout and stderr are the same */
  88.           fputs(buf, stderr);
  89.           fflush(NULL); /* flushes all stdio output streams */
  90.        }


 
unp.h源码:
  1. /* Our own header. Tabs are set for 4 spaces,not 8 */
  2.        #ifndef __unp_h
  3.        #define __unp_h
  4.        #include "/usr/lib/perl5/5.8.0/i386-linux-thread-multi/CORE/config.h"
  5.         /* configuration options for current OS */
  6.                        /* "../config.h" is generated by configure */
  7.        /* If anything changes in the following list of #includes,must change
  8.         acsite.m4 also,for configure's tests */
  9.        #include<sys/types.h> /* basic system data types */
  10.        #include<sys/socket.h> /* basic socket definations */
  11.        #include<sys/time.h> /* timeval{} for select() */
  12.        #include<time.h> /* timespec{} for pselect() */
  13.        #include<netinet/in.h> /* sockaddr_in{} and other Internet defns */
  14.        #include<arpa/inet.h> /* inet(3) functions */
  15.        #include<errno.h>
  16.        #include<fcntl.h> /* for nonblocking */
  17.        #include<netdb.h>
  18.        #include<signal.h>
  19.        #include<stdio.h>
  20.        #include<stdlib.h>
  21.        #include<string.h>
  22.        #include<sys/stat.h> /* for S_xxx file mode constants */
  23.        #include<sys/uio.h> /* for iovec{} and readv /writev */
  24.        #include<unistd.h>
  25.        #include<sys/wait.h>
  26.        #include<sys/un.h> /* for Unix domain sockets */
  27.        #ifdef HAVE_SYS_SELECT_H
  28.        #include<sys/select.h> /* for convenience */
  29.        #endif
  30.        #ifdef HAVE_SYS_SYSCTL_H
  31.        #include<sys/sysctl.h>
  32.        #endif
  33.        #ifdef HAVE_POLL_H
  34.        #include<poll.h> /* for convenience */
  35.        #endif
  36.        #ifdef HAVE_SYS_EVENT_H
  37.        #include<sys/event.h> /* for kqueue */
  38.        #endif
  39.        #ifdef HAVE_STRINGS_H
  40.        #include<strings.h> /* for convenience */
  41.        #endif
  42.        /* Three headers are normally needed for socket/file ioctl's;
  43.         * <sys/ioctl.h>,<sys/fillo.h>,and <sys/sockio.h>.
  44.         */
  45.        #ifdef HAVE_SYS_IOCTL_H
  46.        #include<sys/ioctl.h>
  47.        #endif
  48.        #ifdef HAVE_SYS_FILIO_H
  49.        #include<sys/filio.h>
  50.        #endif
  51.        #ifdef HAVE_SYS_SOCKIO_H
  52.        #include<sys/sockio.h>
  53.        #endif
  54.        #ifdef HAVE_PTHREAD_H
  55.        #include<pthread.h>
  56.        #endif
  57.        #ifdef HAVE_NET_IF_DL_H
  58.        #include<net/if_dl.h>
  59.        #endif
  60.        #ifdef HAVE_NETINET_SCTP_H
  61.        #include<netinet/sctp.h>
  62.        #endif
  63.        /* OSF/1 actually disables recv() and send() in <sys/socket.h> */
  64.        #ifdef __osf__
  65.        #undef recv
  66.        #undef send
  67.        #define recv(a,b,c,d) recvfrom(a,b,c,d,0,0)
  68.        #define send(a,b,c,d) sendto(a,b,c,d,0,0)
  69.        #endif
  70.        #ifndef INADDR_NONE
  71.        #define INADDR_NONE 0xffffffff /* should have been in <netinet/in.h> */
  72.        #endif
  73.        #ifndef SHUT_RD /* these three POSIX names are quite new */
  74.        #define SHUT_RD 0 /* shutdown for reading */
  75.        #define SHUT_WR 1 /* shutdown for writing */
  76.        #define SHUT_RDWR 2 /* shutdown for reading and writing */
  77.        #endif
  78.        #ifndef INET_ADDRSTRLEN
  79.        #define INET_ADDRSTRLEN 16 /* "ddd.ddd.ddd.ddd\0"
  80.                                              1234567890123456 */
  81.        #endif
  82.        /* Define following even if IPv6 not supported,so we can always allocate
  83.         an adequately sized buffer,without #ifdefs in the code. */
  84.        #ifndef INET6_ADDRSRLEN
  85.        #define INET6_ADDRSTRLEN 46 /* max size of IPv6 address string;
  86.                    "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" or
  87.                    "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd\0"
  88.                     1234567890123456789012345678901234567890123456 */
  89.        #endif
  90.        /* Define bzero() as a macro if it's not in standard C library. */
  91.        #ifndef HAVE_BZERO
  92.        #define bzero(ptr,n) memset(ptr,0,n)
  93.        #endif
  94.        /* Older resolves do not have gethostbyname2() */
  95.        #ifndef HAVE_GETHOSTBYNAME2
  96.        #define gethostbyname2(host,family) gethostbyname((host))
  97.        #endif
  98.        /* The structure returned by recvform_flags() */
  99.        struct unp_in_pktinfo{
  100.            struct in_addr ipi_addr; /* dst IPv4 address */
  101.            int ipi_ifindex; /* received interface index */
  102.        };
  103.        /* We need the newer CMSG_LEN() and CMSG_SPACE() macros,but few
  104.         implementations support them today. These two macros really need
  105.         an ALIGN() macro, but each implementation does this differently. */
  106.        #ifndef CMSG_LEN
  107.        #define CMSG_LEN(size) (sizeof(struct cmsghdr)+(size))
  108.        #endif
  109.        #ifndef CMSG_SPACE
  110.        #define CMSG_SPACE(size) (sizeof(struct cmsghdr)+(size))
  111.        #endif
  112.        /* POSIX requires the SUN_LEN() macro, but not all implementations define
  113.          it(yet). Note that this 4.4BSD macro works regardless whether there is
  114.          a length field or not. */
  115.        #ifndef SUN_LEN
  116.        #define SUN_LEN(su) \
  117.           (sizeof(*(su)-sizeof((su)->sun_path)+strlen((su)->sun_path))
  118.        #endif
  119.        /* POSIX renames "Unix domain" as "local IPC".
  120.          But not all systems define AF_LCOAL and PF_LOCAL(yet). */
  121.        #ifndef AF_LOCAL
  122.        #define AF_LOCAL AF_UNIX
  123.        #endif
  124.        #ifndef PF_LOCAL
  125.        #define PF_LOCAL PF_UNIX
  126.        #endif
  127.        /* POSIX requires that an #include of<poll.h> define INFTIM,but many
  128.         systems still define it in <sys/stropts.h>. We don't want to include
  129.         all the streams stuff if it's not needed,so we just define INFTIME here.
  130.         This is the standard value,but there's no guarantee it is -1. */
  131.        #ifndef INFTIM
  132.        #define INFTIM (-1) /* infinite poll timeout */
  133.        #ifdef HAVE_POLL_H
  134.        #define INFTIM_UNPH /* tell unpxti.h we defined it */
  135.        #endif
  136.        #endif
  137.        /* Following could be derived from SOMAXCONN in <sys/socket.h>,but many
  138.         kernels still #define it as 5,while actually supporting many more */
  139.        #define LISTENQ 1024 /* 2nd argument to listen() */
  140.        /* Miscellaneous constants */
  141.        #define MAXLINE 4096 /* max text line length */
  142.        #define BUFFSIZE 8192 /* buffer size for reads and writes */
  143.        /* Define some port number that can be used for our examples */
  144.        #define SERV_PORT 9877 /* TCP and UDP */
  145.        #define SERV_PORT_STR "9877" /* TCP and UDP */
  146.        #define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream */
  147.        #define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram */
  148.        /* Following shortens all the type casts of pointer arguments */
  149.        #define SA struct sockaddr
  150.        #define HAVE_STRUCT_SOCKADDR_STORAGE
  151.        #ifndef HAVE_STRUCT_SOCKADDR_STORAGE
  152.        /*
  153.         * RFC 3493: protocol-independent placeholder for socket addresses
  154.         */
  155.        #define __ss_MAXSIZE 128
  156.        #define __ss_ALIGNSIZE (sizeof(int64_t))
  157.        #ifdef HAVE_SOCKADDR_SA_LEN
  158.        #define __SS_PADlSIZE (__SS_ALIGNSIZE-sizeof(u_char)-sizeof(sa_family_t))
  159.        #else
  160.        #define __SS_PADlSIZE (__SS_ALIGNSIZE-sizeof(sa_family_t))
  161.        #endif
  162.        #define __SS_PAD2SIZE (__SS_MAXSIZE-2*__SS_ALIGNSIZE)
  163.        struct sockaddr_storage{
  164.        #ifdef HAVE_SOCKADDR_SA_LEN
  165.         u_char ss_len;
  166.        #endif
  167.         sa_family_t ss_family;
  168.         char __ss_pad1[__SS_PAD1SIZE];
  169.         int64_t __ss_align;
  170.         char __ss_pad2[__SS_PAD2SIZE];
  171.        };
  172.        #endif
  173.        #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
  174.                          /* default file access permissions for new files */
  175.        #define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
  176.           /* default permissions for new directories */
  177.        typedef void Sigfunc(int); /* for signal handlers */
  178.        #define min(a,b) ((a)<(b)?(a):(b))
  179.        #define max(a,b) ((a)>(b)?(a):(b))
  180.        #ifndef HAVE_ADDRINFO_STRUCT
  181.        #include "../lib/addrinfo.h"
  182.        #endif
  183.        #ifndef HAVE_IF_NAMEINDEX_STRUCT
  184.        struct if_nameindex{
  185.        unsigned int if_index; /* 1,2,... */
  186.        char *if_name; /* null teminated name:""le0,...*/
  187. };
  188. #endif
  189. #ifndef HAVE_TIMESPEC_STRUCT
  190. struct timespec{
  191.     time_t tv_sec;           /* seconds */
  192.     long   tv_nsec;          /* and nanoseconds */
  193. };
  194. #endif

va_start等原理以及应用
一、已知函数中的例子。
  1. INT
  2. PalPrintf(const MMP_CHAR* format, ...) /*…为可变参数,不限定个数和类型.(后面采用专门的指针指向他)*/
  3. {
  4.   
  5.     va_list ap;    //初始化指向可变参数列表的指针
  6.     CHAR buf[384]; //定义存放可变参数转化成格式化字符串的数组。
  7.     INT result;    //定义变量,用于调用函数。
  8.   
  9.     va_start(ap, format);              //将第一个可变参数的地址赋给ap,即ap指向可变参数列表的开始。
  10.     result = vsprintf(buf, format, ap); //将参数ap和format进行转化形成可显示的格式化字符串
  11.     va_end(ap);//将参数ap复位。
  12.   
  13.     if (result >= 0)
  14.     {
  15.         printf(buf); //打印buf数组(字符串数组)
  16.   
  17.     }
  18.   
  19.     return result; // 返回数据给函数调用
  20. }


二、va_start、va_list、va_end、va_arg的应用。

        1. 写一个简单的可变参数的例子      

如何写一个简单的可变参数的C函数.写可变参数的 C函数要在程序中用到以下这些宏: 

  1. void va_start( va_list arg_ptr, prev_param );
  2. type va_arg( va_list arg_ptr, type );
  3. void va_end( va_list arg_ptr );


va在这里是variable-argument(可变参数)的意思. 

这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个 头文件。下面我们写一个简单的可变参数的函数,该函数至少有一个整数参数,第二个参数也是整数,是可选的。函数作用只是打印这两个参数的值.  
 

  1. void simple_va_fun(int i, ...)
  2. {
  3.     va_list arg_ptr;
  4.     int j=0;
  5.      
  6.     va_start(arg_ptr, i);
  7.     j=va_arg(arg_ptr, int);
  8.     va_end(arg_ptr);
  9.     printf("%d %d\n", i, j);
  10.     return;
  11. }

我们可以在我们的头文件中这样声明我们的函数:   
extern void simple_va_fun(int i, ...);

我们在程序中可以这样调用:     
simple_va_fun(100);
simple_va_fun(100,200);

从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:    
  • 首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针. 
  • 然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数.
  • 然后用va_arg返回可变的参数,并赋值给整数j.   va_arg的第二个参数是你要返回的参数的类型,这里是int型. 
  • 最后用va_end宏结束可变参数的获取.然后你就可以在函数里使  用第二个参数了.如果函数有多个可变参数的,依次调用va_arg获取各个参数.   

  如果我们用下面三种方法调用的话,都是合法的,但结果却不一样:
simple_va_fun(100);              //结果是:100 -123456789(会变的值)  
simple_va_fun(100,200);       //结果是:100 200
simple_va_fun(100,200,300);//结果是:100 200 

我们看到第一种调用有错误,第二种调用正确,第三种调用尽管结果正确,但和我们函数最初的设计有突。

2.可变参数在编译器中的处理        
  我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的, 
由于1)硬件平台的不同   2)编译器的不同,所以定义的宏也有所不同,下面以VC++中stdarg.h里x86平台的宏定义摘录如下(’\’号表示折行):  

  1. typedef char * va_list;
  2. #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1))
  3.      
  4. #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
  5.      
  6. #define va_arg(ap,t)   (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
  7.      
  8. #define va_end(ap)      (ap = (va_list)0)
  说明:定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.C语言的函数是从右向左压入堆栈的,图(1)是函数的参数在堆栈中的分布位置.我们看到va_list被定义成char*,有一些平台或操作系统定义为void*.再看va_start的定义,定义为&v+_INTSIZEOF(v),而&v是固定参数在堆栈的地址,所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在堆栈的地址,如图:    
  高地址|-------------------------------------------|    
           |函数返回地址                         |    
           |-------------------------------------------|    
           |.......                                    |    
           |-------------------------------------------|    
           |第n个参数(第一个可变参数)      |    
           |-------------------------------------------|<--va_start后ap指向    
           |第n-1个参数(最后一个固定参数)|    
  低地址|-------------------------------------------|<--   &v    
                   图( 1 )    
   
  然后,我们用va_arg()取得类型t的可变参数值,以上例int型为例,我们看一下va_arg取int型的返回值:    
  j=   (  *(int*)((ap   +=   _INTSIZEOF(int))-_INTSIZEOF(int))  );首先ap+=sizeof(int),已经指向下一个参数的地址了.然后返回ap-sizeof(int)的int*指针,这正是第一个可变参数在堆栈里的地址(图2).然后用*取得这个地址的内容(参数值)赋给j.    
   
  高地址|-------------------------------------------------|    
           |函数返回地址                               |    
           |-------------------------------------------------|    
           |.......                                          |    
           |-------------------------------------------------|<--va_arg后ap指向    
           |第n个参数(第一个可变参数)            |    
           |------------------------------------------------ |<--va_start后ap指向    
           |第n-1个参数(最后一个固定参数)      |    
  低地址|-------------------------------------------------|<--   &v    
                      图(   2   )    
   
最后要说的是va_end宏的意思,x86平台定义为ap=(char*)0;使ap不再 指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的.    在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型. 关于va_start,   va_arg,   va_end的描述就是这些了,我们要注意的是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.   
3.可变参数在编程中要注意的问题   
  因为va_start,   va_arg,   va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型.有人会问:printf中不是实现了智能识别参数吗?那是因为函数printf是从固定参数format字符串来分析出参数的类型,再调用va_arg的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.如果simple_va_fun()改为: 

  1. void simple_va_fun(int i, ...)
  2. {
  3.   va_list arg_ptr;
  4.   char *s=NULL;
  5.      
  6.   va_start(arg_ptr, i);
  7.   s=va_arg(arg_ptr, char*);
  8.   va_end(arg_ptr);
  9.   printf("%d %s\n", i, s);
  10.   return;
  11. }
   可变参数为char*型,当我们忘记用两个参数来调用该函数时,就会出现core   dump(Unix)   或者页面非法的错误(window平台).但也有可能不出错,但错误却是难以发现,不利于我们写出高质量的程序. 

  以下提一下va系列宏的兼容性.   

  System   V   Unix把va_start定义为只有一个参数的宏:  

         va_start(va_list   arg_ptr);   

  而ANSI   C则定义为:     

         va_start(va_list   arg_ptr,   prev_param);  

  如果我们要用system   V的定义,应该用vararg.h头文件中所定义的宏,ANSI   C的宏跟system   V的宏是不兼容的,我们一般都用ANSI   C,所以 用ANSI   C的定义就够了,也便于程序的移植.   
  小结:    

可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实现跟堆栈相关.我们写一个可变函数的C函数时,有利也有弊,所以在不必要的场合,我们无需用到可变参数.如果在C++里,我们应该利用C++的多态性来实现可变参数的功能,尽量避免用C语言的方式来实现. 
-------

vsnprintf

vsnprintf,C语言库函数之一,属于可变参数。用于向字符串中打印数据、数据格式用户自定义。
1函数简介
头文件:
    #include
函数声明:
    int vsnprintf(char *str, size_t size,  const  char  *format,  va_list ap);
参数说明:
    char *str [out],把生成的格式化的字符串存放在这里.
    size_t size [in], str可接受的最大字节数,防止产生数组越界.
    const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。
    va_list ap [in], va_list变量. va:variable-argument:可变参数

函数功能:将可变参数格式化输出到一个字符数组。
    用法类似于vsprintf,不过加了size的限制,防止了内存溢出(size为str所指的存储空间的大小)。
返回值:执行成功,返回写入到字符数组str中的字符个数(不包含终止符),最大不超过size;执行失败,
             返回负 值,并置errno.

备注:
    linux环境下是:vsnprintf;VC6环境下是:_vsnprintf
2用法实例

  1. int mon_log(char* format, ...)
  2. {
  3.     va_list vArgList; //定义一个va_list型的变量,这个变量是指向参数的指针.
  4.     va_start(vArgList, format); // 用va_start宏初始化变量,这个宏的第二个参数是第一个可变参数的
  5.                                 // 前一个参数,是一个固定的参数.
  6.     vsnprintf(str_tmp, 3, format, vArgList);
  7.     va_end(vArgList); //用va_end宏结束可变参数的获取
  8.     return 0;
  9. }
//调用上面的函数
mon_log("%d,%d,%d,%d", 1,2,3,4);
返回值

用法:


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>

  4. char *make_message(const char *fmt, ...)
  5. {
  6.     /* 初始时假设我们只需要不超过100字节大小的空间 */
  7.     int n, size = 100;
  8.     char *p;
  9.     va_list ap;
  10.     if ((p = (char *)malloc(size)) == NULL)
  11.         return NULL;
  12.     while (1) {
  13.         /* 尝试在申请的空间中进行打印操作 */
  14.         va_start(ap, fmt);
  15.         n = vsnprintf (p, size, fmt, ap);
  16.         va_end(ap);
  17.         /* 如果vsnprintf调用成功,返回该字符串 */
  18.         if (n > -1 && n < size)
  19.             return p;
  20.         /* vsnprintf调用失败(n<0)或者p的空间不足够容纳size大小的字符串(n>=size),尝试申请更大的空间*/
  21.         size *= 2; /* 两倍原来大小的空间 */
  22.         if ((p = (char *)realloc(p, size)) == NULL)
  23.             return NULL;
  24. }
  25. }
  26. int main() 
  27. {
  28.     /* 调用上面的函数 */
  29.     char* str = make_message("%d,%d,%d,%d",5,6,7,8);
  30.     printf("%s\n",str);
  31.     free(str); // we allocate the memory in the make_message function, so we should release it
  32.                // by caller(main function).
  33. return 0;
  34. }


阅读(1713) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~