web-dev-qa-db-ja.com

文字列に安全にprintfする最良の方法は?

Printfスタイルの関数の出力を文字列にリダイレクトするための安全な方法を知っている人はいますか?明らかな方法では、バッファオーバーフローが発生します。

何かのようなもの:

string s;
output.beginRedirect( s );  // redirect output to s

... output.print( "%s%d", foo, bar );

output.endRedirect();

問題は「何文字印刷するの?」と聞くのと同じだと思います。アイデア?

16
user48956

このStackOverflowの質問 同様の議論があります。また、その質問では、私のお気に入りのソリューションである、printfと同じ引数を取り、std :: stringを返す「format」関数を紹介します。

4
Larry Gritz

次を使用できます。

std::snprintf 文字を使用している場合*

std::stringstream 文字列を使用する場合(printfとは異なりますが、通常のストリーム関数を使用して文字列を簡単に操作できます)。

boost::format ストリームで機能するprintfに似た関数が必要な場合。 (コメントのjalfによる)

fmt::format これは標準化されており、 std::format

29
Adam Peck

snprintf()関数は文字列に出力しますが、指定された長さだけです。

あなたが探しているものかもしれません...

11
abyx

fmtライブラリfmt::sprintf関数を提供し、printf互換のフォーマット( POSIX仕様 に従った位置引数を含む)を実行し、結果をstd::stringとして返します。 :

std::string s = fmt::sprintf( "%s%d", foo, bar );

免責事項:私はこのライブラリの作者です。

6
vitaut

これを(Cだけでなく)C++としてタグ付けしたので、C++でこの種のことを行う一般的な方法は、printfファミリではなく、 stringstream を使用することです。文字列ストリームによるバッファオーバーフローについて心配する必要はありません。

Boost Format ライブラリは、printfスタイルのフォーマット文字列が好きで、もっと安全なものが必要な場合にも利用できます。

5

古い学校:

_snprintf()
_

書き込まれる数に制限を設定し、実際に書き込まれたサイズを返すことができます。

_asprintf()
_

malloc()を使用して)十分なバッファを割り当て、それがfree()に問題になります。 ʻasprintfはGNU libc関数がBSDlibcに再実装されました。

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.'
4
gnud

C99には、バッファのサイズをパラメータとして受け取るsnprintf関数があります。 GNU Cライブラリにはバッファを割り当てるasprintfがあります。ただし、c ++の場合は、iostreamを使用する方がよい場合があります。

ウィキペディア 詳細があります。

1
Rolf Rander

Printfのフォーマットは、ストリームよりも非常に便利で使いやすいと思います。一方、私はstd :: stringも大好きです。解決策はsprintfを使用することですが、それは任意のバッファサイズを処理できません。

オーバーヘッドなしで一般的なケース(たとえば、バッファが256文字に制限されている)を処理し、それでも大きなバッファを安全に処理する必要があることがわかりました。そのために、クラスにメンバーとして256文字のバッファーを割り当て、snprinfを使用して、そのバッファーとそのサイズを渡します。 snprintfが成功した場合、フォーマットされた文字列をすぐに再調整できます。失敗した場合は、バッファを割り当てて、snprinfを再度呼び出します。バッファはクラスのデストラクタで割り当て解除されます。

1
user3458

Windowsの場合:

StringCchPrintf
StringCbPrintf

からstrsafe.h/lib

0
Johann Gerell