1. 程式人生 > >關於sprintf和snprintf的比較

關於sprintf和snprintf的比較

#include <stdio.h>
#include <string.h>

typedef unsigned char uchar;

#define BUF_SIZE 10						// 緩衝區大小
#define CLEAR_SIZE (BUF_SIZE+2)			// 操作的緩衝區大小, 需要全部重置

void printRuler(int len)
{
	putchar('\n');
	for(int i = 1; i <= len; i++)
	{
		printf("%02d ", i);
		if(i == BUF_SIZE)
			printf("\t|\t");
	}
	putchar('\n');
}

void dis(char *buf, int len)
{
	for(int i = 0; i < len; i++)
	{
		printf("%02x ", (uchar)buf[i]);
		if(i == BUF_SIZE - 1)
			printf("\t|\t");
	}
//	puts("\n");				// 另起一行輸出字串並換行, 不會接在原來的後面
	putchar('\n');			// 直接輸出字元
	printf("buf=[%s]\n\n", buf);
}

int main()
{
	char buf[BUF_SIZE];

	memset(buf, 0xcc, CLEAR_SIZE);
	dis(buf, CLEAR_SIZE);

	printRuler(CLEAR_SIZE);
	printf("-------------------------------------- snprintf\n");

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "12345678");		// 未溢位
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789");		// 未溢位, 剛好填滿
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789A");	// 未溢位, 被截斷1個字元
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789AB");	// 未溢位, 被截斷2個字元
	dis(buf, CLEAR_SIZE);

//////////////////////////////////////////////////////////////////////////////
	printRuler(CLEAR_SIZE);
	printf("-------------------------------------- sprintf\n");
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "12345678");					// 未溢位
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789");				// 剛剛好
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789A");				// 溢位1個字元
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789AB");				// 溢位2個字元
	dis(buf, CLEAR_SIZE);

	return 0;
}

/*
	執行情況:
D:\profile\Desktop\test>make
g++ -o a.exe a.cpp

D:\profile\Desktop\test>a
cc cc cc cc cc cc cc cc cc cc   |       cc cc
buf=[燙燙燙燙燙燙@]


01 02 03 04 05 06 07 08 09 10   |       11 12
-------------------------------------- snprintf
31 32 33 34 35 36 37 38 00 cc   |       cc cc
buf=[12345678]

31 32 33 34 35 36 37 38 39 00   |       cc cc
buf=[123456789]

31 32 33 34 35 36 37 38 39 00   |       cc cc
buf=[123456789]

31 32 33 34 35 36 37 38 39 00   |       cc cc
buf=[123456789]


01 02 03 04 05 06 07 08 09 10   |       11 12
-------------------------------------- sprintf
31 32 33 34 35 36 37 38 00 cc   |       cc cc		// 空間有餘
buf=[12345678]

31 32 33 34 35 36 37 38 39 00   |       cc cc		// 剛好填充満
buf=[123456789]										

31 32 33 34 35 36 37 38 39 41   |       00 cc		// 溢位1個字元
buf=[123456789A]

31 32 33 34 35 36 37 38 39 41   |       42 00		// 溢位2字元
buf=[123456789AB]


	結論:
		1. sprintf和snprintf都會在字串末尾加上'\0'
		2. snprintf比sprintf安全,即不會造成緩衝區溢位
*/

以上的測試環境是GNUMake(windows), 和Linux.

===============================================================================

以下的程式碼測試環境是windows vc6和vc2010

#define _CRT_SECURE_NO_WARNINGS			// 針對vc2010新增

#include <stdio.h>
#include <string.h>

typedef unsigned char uchar;

#ifdef WIN32
	#define snprintf _snprintf			// windows平臺無snprintf, 但是有_snprintf
#endif

#define BUF_SIZE 10						// 緩衝區大小
#define CLEAR_SIZE (BUF_SIZE+2)			// 操作的緩衝區大小, 需要全部重置

void printRuler(int len)
{
	putchar('\n');
	for(int i = 1; i <= len; i++)
	{
		printf("%02d ", i);
		if(i == BUF_SIZE)
			printf("\t|\t");
	}
	putchar('\n');
}

void dis(char *buf, int len)
{
	for(int i = 0; i < len; i++)
	{
		printf("%02x ", (uchar)buf[i]);
		if(i == BUF_SIZE - 1)
			printf("\t|\t");
	}
//	puts("\n");				// 另起一行輸出字串並換行, 不會接在原來的後面
	putchar('\n');			// 直接輸出字元
	printf("buf=[%s]\n\n", buf);
}

int main()
{
	char buf[BUF_SIZE];

	memset(buf, 0xcc, CLEAR_SIZE);
	dis(buf, CLEAR_SIZE);

	printRuler(CLEAR_SIZE);
	printf("-------------------------------------- snprintf\n");

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "12345678");		// 未溢位
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789");		// 未溢位, 剛好填滿
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789A");	// 未溢位, 被截斷1個字元
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	snprintf(buf, BUF_SIZE, "%s", "123456789AB");	// 未溢位, 被截斷2個字元
	dis(buf, CLEAR_SIZE);

//////////////////////////////////////////////////////////////////////////////
	printRuler(CLEAR_SIZE);
	printf("-------------------------------------- sprintf\n");
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "12345678");					// 未溢位
	dis(buf, CLEAR_SIZE);

	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789");				// 剛剛好
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789A");				// 溢位1個字元
	dis(buf, CLEAR_SIZE);
	
	memset(buf, 0xcc, CLEAR_SIZE);
	sprintf(buf, "%s", "123456789AB");				// 溢位2個字元
	dis(buf, CLEAR_SIZE);

	return 0;
}

/*
	執行情況(vc6/vc2010):
	cc cc cc cc cc cc cc cc cc cc   |       cc cc
	buf=[燙燙燙燙燙燙?]


	01 02 03 04 05 06 07 08 09 10   |       11 12
	-------------------------------------- snprintf
	31 32 33 34 35 36 37 38 00 cc   |       cc cc		// 未溢位時會填充字串結束符('\0')
	buf=[12345678]

	31 32 33 34 35 36 37 38 39 00   |       cc cc		// 未溢位時會填充字串結束符('\0')
	buf=[123456789]

	31 32 33 34 35 36 37 38 39 41   |       cc cc		// 溢位了將不會填充字串結束符('\0')
	buf=[123456789A燙?]

	31 32 33 34 35 36 37 38 39 41   |       cc cc		// 溢位了將不會填充字串結束符('\0')
	buf=[123456789A燙?]


	01 02 03 04 05 06 07 08 09 10   |       11 12
	-------------------------------------- sprintf
	31 32 33 34 35 36 37 38 00 cc   |       cc cc
	buf=[12345678]

	31 32 33 34 35 36 37 38 39 00   |       cc cc
	buf=[123456789]

	31 32 33 34 35 36 37 38 39 41   |       00 cc
	buf=[123456789A]

	31 32 33 34 35 36 37 38 39 41   |       42 00
	buf=[123456789AB]

	結論:
		1. windows上無snprintf,但是有_snprintf可以達到同樣的功能,但是細節之處略有不同
		2. 未溢位時,sprintf和snprintf都會在字串末尾加上'\0';
		3. 超出緩衝區大小時,_snprintf不會造成溢位,但是不會在緩衝區中新增字元結束符
		4. sprintf始終會在字串末尾新增結束符,但是存在緩衝區溢位的情況
		5. _snprintf比sprintf安全,即不會造成緩衝區溢位
		6. vc6中對於_snprintf緩衝區溢位時不會出現崩潰資訊,但是在vc2010中卻會出現
*/



相關推薦

關於sprintfsnprintf比較

#include <stdio.h> #include <string.h> typedef unsigned char uchar; #define BUF_SIZE 10 // 緩衝區大小 #define CLEAR_SIZE (B

sprintfsnprintf函數

toc light view 提示 esp 如果 def 數組 oar printf()/sprintf()/snprintf()區別 先貼上其函數原型 printf( const char *format, ...) 格式化輸出字符串,默認輸出到終端-----st

printf、fprintf、sprintfsnprintf 區別

大小 添加 void std 格式化字符串 指定 stdlib.h () div 都是把格式好的字符串輸出,只是輸出的目標不一樣: 1 printf,是把格式字符串輸出到標準輸出(一般是屏幕,可以重定向)。 2 sprintf,是把格式字符串輸出到指定字符串中,所以參數比p

memcpy snprintf的效率比較

#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char **argv) { char *name="17008.1000.32.34.

PHP中echo、print、print_r、printf、sprintfvar_dump的區別比較那些事!

1、echoecho()輸出一個或多個字串。不是一個函式,而是php語句,因此您無需對其使用括號。不過,如果您希望向 echo() 傳遞一個以上的引數,那麼使用括號會發生解析錯誤。而且echo是返回void的,並不返回值,所以不能使用它來賦值。例子: <?php  

關系數據庫NOSQL比較

2個 二級 需求 主鍵 比較 無法 需要 strong ron 關系數據庫 NOSQL 功能: NOSQL 功能簡單 基本只支持主鍵查詢,有的NOSQL支持非主鍵查詢(不過非主鍵查詢時,其性能也很慢),很少有NOSQL支

Java中Integerint比較大小出現的錯誤

最好 裏的 pan 轉換 als 範圍 urn 返回 錯誤 Java在某一處維護著一個常量池,(我記得)在小於128的範圍內,直接用 1 Integer i = 100; 2 int j = 100; 3 return i == j;//true 這裏返回的是true.

C# 的 String.CompareTo Equals==的比較

urn 比較 我們 name pos return www 字母 string String.CompareTo 語法 public int CompareTo( string strB) 返回值 小於 0,實例小於參數 strB; 0,實例等於參數 strB; 大

string中的equals == 的比較

div println new 重寫 logs void 控制臺 static ack 1 package com.pang.string_demo; 2 3 public class Demo01 { 4 public static void main

【轉載】Java中ComparableComparator比較

import 比較器 todo itl 復制代碼 ack div array open 【本文轉自】http://www.cnblogs.com/skywang12345/p/3324788.html Comparable 簡介 Comparable 是排序接口。 若一

Oracle字符時間比較

知識 etime nbsp 間隔 to_date ember 位數 不一致 -m 數據庫中的字段 2017-07-11 13:37:51 類型是char 或者varchar 要進件與 ‘20170625‘ 比較,格式不一致,需要將他轉換成:yyyyMMdd 字符串 1、先

MemcachedRedis比較

計數 select work key-value 網絡io io操作 htm 系統設計 chunk 一、存儲 Memcached基本只支持簡單的key-value存儲方式。Redis除key-value之外,還支持list,set,sorted set,hash等數據結構

JAVA學習(二) String使用equals方法==分別比較的是什麽?(轉)

找到 基礎上 stirng print 大小 obj lis 分配 ret String使用的equals方法和==的區別 equals方法和==的區別 首先大家知道,String既可以作為一個對象來使用,又可以作為一個基本類型來使用。這裏指的作為一個基本類型來使用只是

TCPUDP比較

雙工 tty 才幹 來看 電話 系統 那不 文件 pin 一、TCP/IP協議 TCP/IP協議,你一定常常聽說吧,當中TCP(Transmission Control Protocol)稱為傳輸控制協議,IP(Internet Protocol)稱為

JAXBXStream比較

XML cti unmarshal order add emp 標準 ida 優勢 這兩東東本質上是有差別的,JAXB稱為OX binding工具,XStream應該算序列化工具,但OX binding工具也會marshall和unmarshall,所以包含了序列化這一部分

Java中ComparableComparator比較

collect clas bold 數據 let 排序類 height webkit tom 1、Comparable 介紹 Comparable 是一個排序接口,如果一個類實現了該接口,說明該類本身是可以進行排序的。註意,除了基本數據類型(八大基本數據類型) 的數組或

memcached redis比較

一致性 lis 為什麽 現在 問題 rdb osql dict 比較 同屬於NOSQL存儲,網上流傳很多memcached能做的是redis都可以做,為什麽基本現在兩種都火,原因他們有各自擅長的地方。 memcahed內部采用多核模式,單列運行很快。memcached采用的

Java-IO 字節流的使用效率比較

操作 mp4 tran 方法 區別 讀寫文件 read 內容 ddr 打算做一個系列,前面講了基本的字符流的用法,這篇博客介紹一下字節流的基本用法: 一、基本使用: 基本字節流: FileInputStream FileOutputStream BufferedInpu

[轉載]Linux C 字符串函數 sprintf()、snprintf() 詳解

數組 test 不足 同時 逗號 itoa 表示 成了 nat 一、sprintf() 函數詳解 在將各種類 型的數據構造成字符串時,sprintf 的強大功能很少會讓你失望。 由於 sprintf 跟 printf 在用法上幾乎一樣,只是打印的目的地不同而已,前者打印到字

python2python3比較好的共存方法

python3 col 很多 和數 由於 log 多人 naconda packages 文章根據網絡資料編寫,只為個人學習使用。青山。。。 ---------------------------------------------------- 由於工作學習的需求,大家都