有誰知道將printf樣式函數的輸出重定向到字符串的安全方法嗎?顯而易見的方式會導致緩衝區溢出。安全printf到字符串的最佳方法?
喜歡的東西:
string s;
output.beginRedirect(s); // redirect output to s
... output.print("%s%d", foo, bar);
output.endRedirect();
我認爲這個問題是一樣的問,「有多少個字符將打印生產?」 想法?
有誰知道將printf樣式函數的輸出重定向到字符串的安全方法嗎?顯而易見的方式會導致緩衝區溢出。安全printf到字符串的最佳方法?
喜歡的東西:
string s;
output.beginRedirect(s); // redirect output to s
... output.print("%s%d", foo, bar);
output.endRedirect();
我認爲這個問題是一樣的問,「有多少個字符將打印生產?」 想法?
This StackOverflow question也有類似的討論。同樣在那個問題中,我提出了我最喜歡的解決方案,一個「格式」函數,它接受printf的相同參數並返回一個std :: string。
的snprintf()
功能打印成字符串,但只有儘可能給它的長度。
可能是你在找什麼...
比我快。這是老派的做法。 – dmckee 2009-01-12 18:11:18
您可以使用不需要長度的sprintf。此外,這不會與字符串,因爲他問... – 2009-01-12 18:12:41
您可以使用:
std::snprintf
,如果你是一個char *工作
std::stringstream
,如果你想使用字符串(不相同作爲printf,但將允許您使用普通流功能輕鬆操縱字符串)。
boost::format
如果你想要一個類似於printf的函數來處理流。 (根據jalf的評論)
在C99中,您有snprintf函數,它將緩衝區的大小作爲參數。 GNU C庫有asprintf,爲你分配一個緩衝區。不過,對於C++來說,你可能會更好地使用iostream。
Wikipedia有更多信息。
老同學:
snprintf()
允許你把書面的數量限制,並返回實際寫的大小和
asprintf()
分配(與malloc()
)足夠的緩衝,然後成爲您的問題free()
。 `asprintf是一個現在在BSD libc中重新實現的GNU libc函數。
由於您已將此標記爲C++(而不僅僅是C),因此我會指出在C++中執行此類操作的典型方法是使用stringstream而不是printf系列。無需擔心字符串流的緩衝區溢出問題。
Boost Format庫也可用,如果你喜歡printf風格的格式化字符串,但想要更安全的話。
snprintf()返回寫入整個字符串所需的字節數。 所以,作爲一個小小的例子:
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char* buf = 0;
size_t bufsize = 0;
size_t sz;
const char* format="%s and %s.";
const char* str_1 ="string 1";
const char* str_2 ="string 2";
sz = snprintf(buf, bufsize, format, str_1, str_2);
printf("The buffer needs to be %d bytes.\n", sz);
buf=malloc(sz+1);
if(!buf) {
printf("Can't allocate buffer!\n");
return 1;
}
bufsize = sz+1;
buf[bufsize-1] = '\0';
sz = snprintf(buf, bufsize, format, str_1, str_2);
printf("Filled buffer with %d bytes.\n", sz);
printf("The buffer contains:\n'%s'\n", buf);
return 0;
}
輸出:
The buffer needs to be 22 bytes.
Filled buffer with 22 bytes.
The buffer contains:
'string 1 and string 2.'
在Windows上:
StringCchPrintf
StringCbPrintf
從strsafe.h/lib
。
我發現printf格式比流更容易使用和使用。另一方面,我也很喜歡std :: string。解決方案是使用sprintf,但不能處理任意的緩衝區大小。
我發現我需要處理常見的情況(比如,緩衝區限制爲256個字符),而不是 開銷,並且安全地處理大型緩衝區。爲此,我有一個256字節的緩衝區,作爲成員放在我的課程中,我使用snprinf,傳遞該緩衝區及其大小。如果snprintf成功,我可以立即重新格式化字符串。如果失敗,我分配緩衝區並再次調用snprinf。該緩衝區在類的析構函數中被釋放。
The fmt library提供fmt::sprintf
功能執行printf的兼容格式(包括根據POSIX specification位置參數),並返回其結果作爲std::string
:
std::string s = fmt::sprintf("%s%d", foo, bar);
聲明:我此庫的作者。
不適用於任何其他符合標準的實現,所以yuck。 – Bklyn 2009-01-12 22:18:07
此外,唯一的區別是,如果「安全」crt檢測到某些未定義的行爲,它會自行崩潰。這並不能繞過他遇到的問題。 – 2014-08-19 19:47:48