Page's Personal Website

Snprintf知多少

2016-11-17
c++

[TOC]

在编写代码或者找bug的情况下,你最终会停留在下面几个问题上:

  • 1.在vs上面编译和测试都没问题了,为什么Linux下却找不到函数?
  • 2._snprintf在vs上面测试通过,为什么到snprintf到linux下面却又有bug呢?
  • 3.我下面的用法到底有什么问题?

代码:

char szContent[256] = {0};
int nLen = snprintf(szContent, sizeof(szContent)-1, "%s:%s", pszName, pszMsg)
memcpy(pHeader, szContent, nLen)

下面就对这些函数分别在什么环境下使用以及细微的区别做个总结,希望对有些跟我一样的人有些许帮助。^_^

sprintf

  • 原型
	int sprintf ( char * str, const char * format, ... );
  • 平台

windows和linux

  • 比较

sprintf和printf最大的区别是输出到不同的地方,前者是字符串,后者是终端。windows和linux区别不大,遇见了再补充。

snprintf

  • 原型
	int snprintf ( char * s, size_t n, const char * format, ... );

说明:最多从源串中拷贝 n - 1 个字符到目标串中,然后再在后面加一个 0 。所以如果目标串的大小为 n的话,将不会溢出,但是返回值有问题,看下面。

  • 平台

linux

  • 结束符

最值得注意的:snprintf(linux)版本会自动在后面加’/0’,同时复制的长度也包含了’\0’。_snprintf(windows)版本只是简单的复制指定长度的字符,不自动加’\0’,并且长度也不包含’\0’。

看一个例子印象会深刻不少[2],看源码:

#include <stdio.h>
#include <string.h>
int main()
{
    char buf[20];
    char *pstr = "this is a test string";

    memset(buf, 0, sizeof(buf));
	// Notice: return value!
    int len = snprintf(buf, sizeof(buf)-1, "%s", pstr);

    printf("buf = %s, strlen(buf) = %d, len = %d\n", buf, strlen(buf), len);

    return 0;

}

结果:

// linux的snprintf
buf = this is a test str, strlen(buf) = 18, len = 21

// windows的_snprintf
buf = this is a test stri, strlen(buf) = 19, nLen = -1
  • 返回值

c++标准定义

The number of characters that would have been written if n had been sufficiently large, not counting the terminating null character. If an encoding error occurs, a negative number is returned. Notice that only when this returned value is non-negative and less than n, the string has been completely written.

Linux下的返回值:返回你想写入的字符个数,也就是当想写入的字符串大于n的时候,返回的不是n,而是这个想写入的字符个数。当出现编码错误的时候才会返回负数!

见上面结束符的代码例子,看到最后打印的nLen就很明显了。

_snprintf

  • 原型
	int _snprintf( char *buffer, size_t count, const char *format [, argument] ... );

官网定义

_snprintf returns the number of bytes stored in buffer, not counting the terminating null character. If the number of bytes required to store the data exceeds count, then count bytes of data are stored in buffer and a negative value is returned.

总的来说,’\0’他是不管的。如果你很本分,格式化串的长度小于第二个参数count的话,那就在结尾给你填一个结束符’\0’,否则的话自求多福~~。

  • 平台

windows

  • 结束符

见snprintf代码例子

  • 返回值

_snprintf returns the number of bytes stored in buffer, not counting the terminating null character. If the number of bytes required to store the data exceeds count, then count bytes of data are stored in buffer and a negative value is returned. _snwprintf returns the number of wide characters stored in buffer, not counting the terminating null wide character. If the storage required to store the data exceeds count wide characters, then count wide characters are stored in buffer and a negative value is returned.

可见当超出了范围,返回值为负数,返回值还是不要拿来用!!!例子见snprintf代码例子

_s安全版本

  • 原型

  • 平台
  • windows

总结

  1. sprintf在windows和linux下面都有;
  2. 但是snprintf是在linux下的,而_snprintf是在windows下的是,所以双端都写的人需要注意一下;
  3. snprinf(linux)和_snprinf(windows)是相对应的,最重要的注意区别是会不会主动增加’\0’,以及copy的长度是否包含’\0’;
  4. snprinf(linux)和_snprinf(windows)还有一个坑是返回值,所以但凡使用到返回值一定要谨慎再谨慎!
  5. _s是微软提出来的安全版本,所以只有windows下面才能使用。

参考

[1]snprintf函数使用(Windows与Linux版本)

[2]snprintf linux 与 windows下差异


Comments

Content