snprintf笔记
在weibo上看到Laruence大神修复了一个使用snprintf的bug (http://t.cn/Rm6AuFh) 引起了TK教主的关注。TK教主着重提到了在windows下snprintf与_snprintf的行为有差别。
想想自己之前也在windows下写过代码,因具体的使用场景没有触发这种差异,因而对此也没有特别留意。下面对此写代码和查MSDN了具体验证了差别,结果记录如下。
先说snprintf,相信只要写过C代码的程序员,肯定用过这个C库函数,其声明如下
int snprintf(char *str, size_t size, const char *format, ...);
其向 str 为起始地址,长度为 size 的buffer中,按 format 指定的格式进行格式化写入串。size 限制了最大向 str 写入的字节数,但具体根据 format 格式和给定的额外参数,实际拼接出的串长度会超过 size。此时的结果就需要特别注意。man中对snprintf的说明如下
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to
this limit, then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if
enough space had been available. Thus, a return value of size or more means that the output was truncated. (See also below under NOTES.)
返回值是要特别注意的,并不是是向 str 写入的字节数,而是 format 和对应实参拼接出的串长度(称为len, 不包含尾部0字节)。
当 len 小于 size 时,除了将该串写入buffer之外,还额外追加一个0字节。
当 len 等于 size 时,将该串写入buffer之后,会将最后字节清零,该串位内容未字节也就被截断了。
当 len 大于 size 时,最多写入该串前(size-1)个字节,并将第 size 个字节清零。
snprintf 在 linux 下(libc-2.23.so) 和 windows 下(VS2015 VCRUNTIME140)行为一致,都是如上所述。
但在windows下 _snprintf 的行为和snprintf不完全一致。
当 len 小于 size 时,除了将该串写入buffer之外,还额外追加一个0字节,和 snprintf 相同
当 len 等于 size 时,直接将串写入buffer,并不会对尾字节清零,返回值为 len,和 snprintf 不同
当 len 大于 size 时,直接将串写入buffer,并不将第 size 个字节清零,返回值为 -1,和 snprintf 不同
MSDN对应的说明如下
Let len be the length of the formatted data string, not including the terminating null. len and count are in bytes for _snprintf, wide characters for _snwprintf.
If len < count, len characters are stored in buffer, a null-terminator is appended, and len is returned.
If len = count, len characters are stored in buffer, no null-terminator is appended, and len is returned.
If len > count, count characters are stored in buffer, no null-terminator is appended, and a negative value is returned.
实际使用如下代码进行测试,结果如下,注释中是 GDB 查看的中间结果。
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#define snprintf _snprintf
#endif
int main(int argc, char *argv[])
{
char buffer[16];
int ret;
/*
(gdb) p ret
$1 = 4
(gdb) x /16bx buffer
0x7ffffffde250: 0x31 0x32 0x33 0x34 0x00 0x01 0x01 0x01
0x7ffffffde258: 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
*/
memset(buffer, 1, sizeof(buffer));
ret = snprintf(buffer, 8, "%s", "1234");
/*
(gdb) p ret
$2 = 8
(gdb) x /16bx buffer
0x7ffffffde250: 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x00
0x7ffffffde258: 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
*/
memset(buffer, 1, sizeof(buffer));
ret = snprintf(buffer, 8, "%s", "12345678");
/*
(gdb) p ret
$3 = 9
(gdb) x /16bx buffer
0x7ffffffde250: 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x00
0x7ffffffde258: 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
*/
memset(buffer, 1, sizeof(buffer));
ret = snprintf(buffer, 8, "%s", "123456789");
return 0;
}
而在VS下,查看的中间结果, snprintf 和 _snprintf 分别如下
snprintf
ret = 4
buffer: 31 32 33 34 00, 01 01 01 01 01 01 01 01 01 01 01
ret = 8
buffer: 31 32 33 34 35 36 37 00, 01 01 01 01 01 01 01 01
ret = 9
buffer: 31 32 33 34 35 36 37 00, 01 01 01 01 01 01 01 01
_snprintf
ret = 4
buffer: 31 32 33 34 00, 01 01 01 01 01 01 01 01 01 01 01
ret = 8
buffer: 31 32 33 34 35 36 37 38, 01 01 01 01 01 01 01 01
ret = -1
buffer: 31 32 33 34 35 36 37 38, 01 01 01 01 01 01 01 01
snprintf笔记的更多相关文章
- 《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)
<Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h> ...
- sc7731 Android 5.1 LCD驱动简明笔记之三
此篇笔记基于sc7731 - android 5.1,对lcd的gralloc库做一个简明笔记. 第一部分 调用gralloc.sc8830.so所谓的Gralloc模块,它就是一个模块,一个操作ke ...
- 错误内存【读书笔记】C程序中常见的内存操作有关的典型编程错误
题记:写这篇博客要主是加深自己对错误内存的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 对C/C++程序员来讲,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的 ...
- Linux进程间通信IPC学习笔记之管道
基础知识: 管道是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)没有名字: 2)用于共同祖先间的进程通信: 3)读写操作用read和write函数 #incl ...
- redis 学习笔记一
找了半天,发觉还是redis的源码看起来比较舒服.所以决定今年把redis的源码读一遍顺便做个读书笔记.好好记录下.话说现在越来不越不愿意用脑袋来记录东西,喜欢靠note来记.话说这样不爱用脑会不会过 ...
- 用gdb调试程序笔记: 以段错误(Segmental fault)为例
用gdb调试程序笔记: 以段错误(Segmental fault)为例[转] 1.背景介绍2.程序中常见的bug分类3.程序调试器(如gdb)有什么用4.段错误(Segmental fault)介绍5 ...
- 树莓派学习笔记——使用文件IO操作GPIO SysFs方式
0 前言 本文描写叙述假设通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先訪问/sys/class/gpio文件夹,向export文件写入GPIO编号, ...
- 【unix网络编程第三版】阅读笔记(二):套接字编程简介
unp第二章主要将了TCP和UDP的简介,这些在<TCP/IP详解>和<计算机网络>等书中有很多细致的讲解,可以参考本人的这篇博客[计算机网络 第五版]阅读笔记之五:运输层,这 ...
- Muduo学习笔记(一) 什么都不做的EventLoop
Muduo学习笔记(一) 什么都不做的EventLoop EventLoop EventLoop的基本接口包括构造.析构.loop(). One Loop Per Thread 一个线程只有一个Eve ...
随机推荐
- zabbix实现对磁盘性能动态监控
前言 zabbix一直是小规模互联网公司服务器性能监控首选,首先是免费,其次,有专门的公司和社区开发维护,使其稳定性和功能都在不断地增强和完善.zabbix拥有详细的UI界面和分组策略,在被监控的服务 ...
- Ubuntu系统建立交叉编译环境
飞凌 FET6818核心板 解压编译器: tar zxvf arm-cortex_a9_eabi-4.7-eglibc-2.18.tar.gz -C/opt 设置默认编译环境: vi /etc/pr ...
- 使用本机IP调试web项目
1.查看本机IP 使用命令行查看本机ip地址: cmd 进入命令行 Ipconfig 查询本机ip. 2.找到启动项目的配置文件 启动IIS查找配置文件的位置 点击显示所有应用程序 3.修改项 ...
- Linux的常识
用到$是环境变量查询的开头 # echo $LANG查看编码 ls -l 是查看本地的所有文件的目录 以list的形式罗列出来 cd .. 上一层的目录 查看当前目录下有哪些文件 ll 等于ls -l ...
- selenium自动化实例: 多层框架中关于iframe的定位,以及select下拉框选择
对于一个自动化的初学者来说会很常见的遇到元素明明存在却始终定位不到, 从而导致脚本报错,当然定位不到元素的原因很多, 其中一种就是多层框架iframe导致的 下方截图示意: 下方为写脚本时候的示例并其 ...
- bzoj2748
题解: 简单dp 代码: #include<bits/stdc++.h> using namespace std; ; int n,x,m,a[N],f[N][N]; int main() ...
- 浅谈redis的HyperLogLog与布隆过滤器
首先,HyperLogLog与布隆过滤器都是针对大数据统计存储应用场景下的知名算法. HyperLogLog是在大数据的情况下关于数据基数的空间复杂度优化实现,布隆过滤器是在大数据情况下关于检索一个元 ...
- cvte春招测试面试记录
cvte春招测试面试记录,挂在了综合面试(hr面)...尽量回忆面试的问题(可能不完全). 技术面一面: 1.自我介绍 2.根据实习项目问,智能客服怎么测正确率之类的. 3.测试人脸解锁 4.测试微信 ...
- Problem 7: 10001st prime
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. ...
- jquery slideDown 控制div出现的方向
.custom-popup { position: absolute; /*top: 0;*/ 上向下 ; 下向上 ; ; display: none; width: 100%; height: 10 ...