GVKun编程网logo

snprintf和sprintf区别分析(snprintf和sprintf的区别)

13

对于snprintf和sprintf区别分析感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解snprintf和sprintf的区别,并且为您提供关于C++中的sprintf和snprintf

对于snprintf和sprintf区别分析感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解snprintf和sprintf的区别,并且为您提供关于C++ 中的sprintf和snprintf 函数的区别、C中printf、sprintf和fprintf的区别(代码示例)、C语言中printf,sprintf和fprintf的区别是什么、echo, print, printf 和 sprintf 区别_php技巧的宝贵知识。

本文目录一览:

snprintf和sprintf区别分析(snprintf和sprintf的区别)

snprintf和sprintf区别分析(snprintf和sprintf的区别)

今天在项目中使用snprintf时遇到一个比较迷惑的问题,追根溯源了一下,在此对sprintf和snprintf进行一下对比分析。

因为sprintf可能导致缓冲区溢出问题而不被推荐使用,所以在项目中我一直优先选择使用snprintf函数,虽然会稍微麻烦那么一点点。这里就是sprintf和snprintf最主要的区别:snprintf通过提供缓冲区的可用大小传入参数来保证缓冲区的不溢出,如果超出缓冲区大小则进行截断。但是对于snprintf函数,还有一些细微的差别需要注意。

snprintf函数的返回值

sprintf函数返回的是实际输出到字符串缓冲中的字符个数,包括null结束符。而snprintf函数返回的是应该输出到字符串缓冲的字符个数,所以snprintf的返回值可能大于给定的可用缓冲大小以及最终得到的字符串长度。看代码最清楚不过了:

char tlist_3[10] = {0};
    int len_3 = 0;

    len_3 = snprintf(tlist_3,10,"this is a overflow test!\n");
    printf("len_3 = %d,tlist_3 = %s\n",len_3,tlist_3);
上述代码段的输出结果如下:

len_3 = 25,tlist_3 = this is a
所以在使用snprintf函数的返回值时,需要小心慎重,避免人为造成的缓冲区溢出,不然得不偿失。

snprintf函数的字符串缓冲

int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
上面的函数原型大家都非常熟悉,我一直以为snprintf除了多一个缓冲区大小参数外,表现行为都和sprintf一致,直到今天遇上的bug。在此之前我把下面的代码段的两个输出视为一致。

char tlist_1[1024] = {0},tlist_2[1024]={0};
    char fname[7][8] = {"a1","b1","c1","d1","e1","f1","g1"};
    int i = 0, len_1,len_2 = 0;

    len_1 = snprintf(tlist_1,1024,"%s;",fname[0]);
    len_2 = snprintf(tlist_2,1024,"%s;",fname[0]);

    for(i=1;i<7;i++)
    {
        len_1 = snprintf(tlist_1,1024,"%s%s;",tlist_1,fname[i]);
        len_2 = sprintf(tlist_2,"%s%s;",tlist_2,fname[i]);
    }

    printf("tlist_1: %s\n",tlist_1);
    printf("tlist_2: %s\n",tlist_2);
可实际上得到的输出结果却是:

tlist_1: g1;
tlist_2: a1;b1;c1;d1;e1;f1;g1;
知其然就应该知其所以然,这是良好的求知态度,所以果断翻glibc的源代码去,不凭空想当然。下面用代码说话,这就是开源的好处之一。首先看snprintf的实现:

glibc-2.18/stdio-common/snprintf.c:
 18 #include <stdarg.h>
 19 #include <stdio.h>
 20 #include <libioP.h>
 21 #define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 22
 23 /* Write formatted output into S, according to the format
 24    string FORMAT, writing no more than MAXLEN characters.  */
 25 /* VARARGS3 */
 26 int
 27 __snprintf (char *s, size_t maxlen, const char *format, ...)
 28 {
 29   va_list arg;
 30   int done;
 31
 32   va_start (arg, format);
 33   done = __vsnprintf (s, maxlen, format, arg);
 34   va_end (arg);
 35
 36   return done;
 37 }
 38 ldbl_weak_alias (__snprintf, snprintf)
使用_IO_vsnprintf函数实现:

glibc-2.18/libio/vsnprintf.c:
 94 int
 95 _IO_vsnprintf (string, maxlen, format, args)
 96      char *string;
 97      _IO_size_t maxlen;
 98      const char *format;
 99      _IO_va_list args;
100 {
101   _IO_strnfile sf;
102   int ret;
103 #ifdef _IO_MTSAFE_IO
104   sf.f._sbf._f._lock = NULL;
105 #endif
106
107   /* We need to handle the special case where MAXLEN is 0.  Use the
108      overflow buffer right from the start.  */
109   if (maxlen == 0)
110     {
111       string = sf.overflow_buf;
112       maxlen = sizeof (sf.overflow_buf);
113     }
114
115   _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
116   _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
117   string[0] = ''\0'';
118   _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
119   ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
120
121   if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
122     *sf.f._sbf._f._IO_write_ptr = ''\0'';
123   return ret;
124 }
关键点出来了,源文件第117行string[0] = ''\0'';把字符串缓冲先清空后才进行实际的输出操作。那sprintf是不是就没有清空这个操作呢,继续代码比较中,sprintf的实现:

glibc-2.18/stdio-common/snprintf.c:
 18 #include <stdarg.h>
 19 #include <stdio.h>
 20 #include <libioP.h>
 21 #define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
 22
 23 /* Write formatted output into S, according to the format string FORMAT.  */
 24 /* VARARGS2 */
 25 int
 26 __sprintf (char *s, const char *format, ...)
 27 {
 28   va_list arg;
 29   int done;
 30
 31   va_start (arg, format);
 32   done = vsprintf (s, format, arg);
 33   va_end (arg);
 34
 35   return done;
 36 }
 37 ldbl_hidden_def (__sprintf, sprintf)
 38 ldbl_strong_alias (__sprintf, sprintf)
 39 ldbl_strong_alias (__sprintf, _IO_sprintf)
使用_IO_vsprintf而不是_IO_vsnprintf函数,_IO_vsprintf函数实现:

glibc-2.18/libio/iovsprintf.c:
 27 #include "libioP.h"
 28 #include "strfile.h"
 29
 30 int
 31 __IO_vsprintf (char *string, const char *format, _IO_va_list args)
 32 {
 33   _IO_strfile sf;
 34   int ret;
 35
 36 #ifdef _IO_MTSAFE_IO
 37   sf._sbf._f._lock = NULL;
 38 #endif
 39   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
 40   _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
 41   _IO_str_init_static_internal (&sf, string, -1, string);
 42   ret = _IO_vfprintf (&sf._sbf._f, format, args);
 43   _IO_putc_unlocked (''\0'', &sf._sbf._f);
 44   return ret;
 45 }
 46 ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)
 47
 48 ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
 49 ldbl_weak_alias (__IO_vsprintf, vsprintf)
在40行到42行之间没有进行字符串缓冲的清空操作,一切了然。

一开始是打算使用gdb调试跟踪进入snprintf函数探个究竟的,可是调试时发现用step和stepi都进不到snprintf函数里面去,看了一下链接的动态库,原来libc库已经stripped掉了:

hong@ubuntu:~/test/test-example$ ldd snprintf_test
        linux-gate.so.1 =>  (0xb76f7000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7542000)
        /lib/ld-linux.so.2 (0xb76f8000)
hong@ubuntu:~/test/test-example$ file /lib/i386-linux-gnu/libc.so.6
/lib/i386-linux-gnu/libc.so.6: symbolic link to `libc-2.15.so''
lzhong@ubuntu:~/test/test-example$ file /lib/i386-linux-gnu/libc-2.15.so
/lib/i386-linux-gnu/libc-2.15.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=0x7a6dfa392663d14bfb03df1f104a0db8604eec6e, for GNU/Linux 2.6.24, stripped
所以只能去找 ftp://ftp.gnu.org/gnu/glibc官网啃源代码了。

在找glibc源码时,我想知道系统当前使用的glibc版本,一时不知道怎么查,Google一下大多数都是Redhat上的rpm查法,不适用于Ubuntn,而用dpkg和aptitude show都查不到glibc package,后来才找到ldd用法。

hong@ubuntu:~/test/test-example$ ldd --version
ldd (Ubuntu EGLIBC 2.15-0ubuntu20) 2.15
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
现在才发现Ubuntn用的是好像是EGLIBC,而不是标准的glibc库。其实上面ldd snprintf_test查看应用程序的链接库的方法可以更快速地知道程序链接的glibc版本。

C++ 中的sprintf和snprintf 函数的区别

C++ 中的sprintf和snprintf 函数的区别

在编程过程中经常有字符串转数字和数字转字符串,相应的函数大家最经常见到可能是atoi和itoa。但是itoa不是标准库里面的函数,所以接下来介绍下面两个函数sprintf和snprintf函数,并将它们比较一番。

sprintf()函数

用法

int sprintf(char *string,char *format,arg_list);

###说明 数sprintf()的用法和printf()函数一样,只是sprintf()函数给出第一个参数string(一般为字符数组),然后再调用 outtextxy()函数将串里的字符显示在屏幕上。arg_list为参数表,可有不定个数。通常在绘图方式下输出数字时可调用sprintf()函 数将所要输出的格式送到第一个参数,然后显示输出。

snprintf函数

snprintf函数是sprintf的限制字符数量的一个表达。

###用法

int snprintf(char *str, size_t size, const char *format, ...)

###snprintf函数的返回值

sprintf函数返回的是实际输出到字符串缓冲中的字符个数,包括null结束符。而snprintf函数返回的是应该输出到字符串缓冲的字符个数,所以snprintf的返回值可能大于给定的可用缓冲大小以及最终得到的字符串长度

总结

sprintf可能导致缓冲区溢出问题而不被推荐使用,所以在项目中我一直优先选择使用snprintf函数,虽然会稍微麻烦那么一点点。这里就是sprintf和snprintf最主要的区别:snprintf通过提供缓冲区的可用大小传入参数来保证缓冲区的不溢出,如果超出缓冲区大小则进行截断。但是对于snprintf函数,还有一些细微的差别需要注意。

C中printf、sprintf和fprintf的区别(代码示例)

C中printf、sprintf和fprintf的区别(代码示例)

本篇文章主要给大家介绍C语言中printf、sprintf和fprintf的区别,希望对需要的朋友有所帮助!

printf:

printf函数用于在stdout(标准输出)控制台打印字符流数据。

语法:

int printf(const char* str, ...);

示例:

#include<stdio.h> 
int main() 
{ 
   printf(hello geeksquiz); 
   return 0; 
}

输出:

hello geeksquiz

sprintf:

语法:

int sprintf(char *str, const char *string,...);

sprintf用于将格式化文本(字符串/字符流)打印到字符串缓冲区上。

示例:

#include<stdio.h> 
int main() 
{ 
    char buffer[50]; 
    int a = 10, b = 20, c; 
    c = a + b; 
    sprintf(buffer, Sum of %d and %d is %d, a, b, c); 
    printf(%s, buffer); 
  
    return 0; 
}

输出:

Sum of 10 and 20 is 30

fprintf:

fprintf用于在文件中打印字符串内容,但不在stdout(标准输出)控制台上打印。

int fprintf(FILE *fptr, const char *str, ...);

示例:

#include<stdio.h> 
int main() 
{ 
    int i, n=2; 
    char str[50]; 
  
    FILE *fptr = fopen(sample.txt, w); 
    if (fptr == NULL) 
    { 
        printf(Could not open file); 
        return 0; 
    } 
  
    for (i=0; i<n; i++) 
    { 
        puts(Enter a name); 
        gets(str); 
        fprintf(fptr,%d.%s\n, i, str); 
    } 
    fclose(fptr); 
  
    return 0; 
}
输入: GeeksforGeeks
       GeeksQuiz
输出:  sample.txt file Now having output as 
0. GeeksforGeeks
1. GeeksQuiz

相关推荐:《C教程》

C语言中printf,sprintf和fprintf的区别是什么

C语言中printf,sprintf和fprintf的区别是什么

printf,sprintf和fprintf都是c语言的输出语句,都是把格式好的字符串输出。那么这三者有什么区别,下面本篇文章就来认识一下printf,sprintf和fprintf,介绍它们之间的区别,希望对大家有所帮助。

C语言中printf,sprintf和fprintf的区别是什么

printf

printf函数用于在标准输出设备(stdout控制台)上输出文本(字符串/字符流)或值。

基本语法

int printf(const char * format,...);
登录后复制

说明:

立即学习“C语言免费学习笔记(深入)”;

format提供了文本字符串的格式,该格式将在输出设备上使用%s,%d,%f等格式说明符进行输出。

...提供需要输出的参数列表。

返回类型int返回屏幕上输出的字符总数。

示例:

#include<stdio.h> 
int main() 
{ 
   printf("hello geeksquiz"); 
    printf("\n"); 
   int  a=2;
   printf("%d",a); 
   return 0; 
}
登录后复制

输出:

2.jpg

sprintf

sprintf用于将格式化文本(字符串/字符流)发送(复制)到字符串缓冲区上。

基本语法

int sprintf(char * str,const char * format,...);
登录后复制

说明:

立即学习“C语言免费学习笔记(深入)”;

char * str : 将在其中发送(复制)格式化文本的字符数组。

format在格式说明符的帮助下提供格式化文本。

...提供需要输出的参数列表。

● 返回类型int将复制(发送)字符的总数返回到char * str中。

示例:

#include <stdio.h>
int main()
{
    char str[100];
    int n;
    
    n=sprintf((char*)str,"我的名字是%s, I am %d years old.","Mike",23);
    
    printf("Text is: %s\n",str);
    printf("Total number of copied characters are: %d\n",n);
    return 0;
}
登录后复制

说明:sprintf将字符串存储在指定的char缓冲区上,再通过printf在stdout控制台上输出。

输出:

3.jpg

fprintf

fprintf用于在文件中输出字符串内容,但不在stdout控制台上输出。

基本语法:

int fprintf(FILE * fptr,const char * str,...);
登录后复制

说明:

立即学习“C语言免费学习笔记(深入)”;

fptr :这是指向 FILE 对象的指针,该 FILE 对象标识了流。

str:这是 C 字符串,包含了要被写入到流 stream 中的文本。

示例:

#include<stdio.h> 
int main() 
{ 
    int i, n=2; 
    char str[50]; 
  
    //open file sample.txt in write mode 
    FILE *fptr = fopen("sample.txt", "w"); 
    if (fptr == NULL) 
    { 
        printf("无法打开文件"); 
        return 0; 
    } 
  
    for (i=0; i<n; i++) 
    { 
        puts("输入名称"); 
        gets(str); 
        fprintf(fptr,"%d.%s\n", i, str); 
    } 
    fclose(fptr); 
  
    return 0; 
}
登录后复制

输出:

360截图20190125164812469.jpg

sample.txt中:

4.jpg

总结:

printf,sprintf和fprintf的区别是:它们的输出目标不一样。printf在stdout控制台上输出数据字符流;sprintf将数据字符流发送指定的char缓冲区上;fprintf用于在文件中输出字符串内容。

以上就是本篇文章的全部内容,希望能对大家的学习有所帮助。更多精彩内容大家可以关注php中文网相关教程栏目!!!

以上就是C语言中printf,sprintf和fprintf的区别是什么的详细内容,更多请关注php中文网其它相关文章!

echo, print, printf 和 sprintf 区别_php技巧

echo, print, printf 和 sprintf 区别_php技巧

- echo 

是命令,不能返回值。echo后面可以跟很多个参数,之间用分号隔开,如: 
echo $myvar1; 
echo 1,2,$myvar,"bold"; 

- print 

是函数,可以返回一个值,只能有一个参数。 

- printf 

函数,把文字格式化以后输出,如: 
$name="hunte"; 
$age=25; 
printf("my name is %s, age %d", $name, $age); 

- sprintf 

跟printf相似,但不打印,而是返回格式化后的文字,其他的与printf一样。 
- echo 

是命令,不能返回值。echo后面可以跟很多个参数,之间用分号隔开,如: 
echo $myvar1; 
echo 1,2,$myvar,"bold"; 

- print 

是函数,可以返回一个值,只能有一个参数。 

- printf 

函数,把文字格式化以后输出,如: 
$name="hunte"; 
$age=25; 
printf("my name is %s, age %d", $name, $age); 

- sprintf 

跟printf相似,但不打印,而是返回格式化后的文字,其他的与printf一样。

关于snprintf和sprintf区别分析snprintf和sprintf的区别的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于C++ 中的sprintf和snprintf 函数的区别、C中printf、sprintf和fprintf的区别(代码示例)、C语言中printf,sprintf和fprintf的区别是什么、echo, print, printf 和 sprintf 区别_php技巧的相关信息,请在本站寻找。

本文标签: