1

動的言語で printf() アナログを実装する賢い方法に興味があります。問題は、引数リストに深くネストされたデータ型が含まれている可能性があるため、最終バッファにどれだけのメモリを割り当てる必要があるかを簡単に知ることができないことです。これを行うための明白な方法は、引数を介して 2 つのパスを作成することです。1 つはバッファ サイズを推定し、もう 1 つは実際に文字列をフォーマットします。これを行うより良い方法はありますか?

明確化: Erlang 用の C 関数を書くことを考えています。Erlangs のデータ型は非常にボックス化されているため、asprintf のような関数を使用するには、すべてのボックス化を解除する必要があり (おそらくは formatstring を書き換える必要があります)、これにはコストがかかります。

4

2 に答える 2

2

エミュレートしようとしているのであればprintf、問題はありません。バッファーは必要ないため、見つけたときに各トークンをコンソールに書き込みます。

エミュレートしようとしている場合はsprintf、質問を更新する必要があります。

sprintf の場合。. . 拡張可能な文字列バッファを使用します。

自分でロールバックする必要がある場合は、512 バイトの妥当なバッファーから始めてください。この制限に達すると、以前の制限の2 倍の別のバッファーを割り当て (最初は 1024、2 回目は 2048 など)、バッファー 1 をバッファー 2 にコピーし、新しいバッファーを古いものと交換して、破棄/解放/削除/割り当て解除します。最初のバッファ。

終了したら、正しい長さの文字列を割り当て、バッファを文字列にコピーして返します。

バッファが技術的に大きすぎて、おそらくほとんど使用されていない場合でも、結果としてバッファを返すことを気にしない場合、最後のステップは無視できます。

更新
再割り当てのため、次善のソリューションのように感じます。私が間違っている?

一言で言えば、そうです。
これは、動的リストと配列が C++ STL や .Net フレームワークなどの主要なフレームワークに実装されている方法です。フォーマットが 512 バイトを破る可能性を考慮した場合、1024 または 2048 を破る可能性はどれくらいですか? 文字列が長くなった場合、それは 3 つの余分なコピーです。おそらく、80% の確率で最初の 512 制限に達することはないという 80/20 ルールを適用できます (最初の割り当てを 64 バイトに落として、80/20 ルールを適用することもできます)。

ここで、書式設定する項目を 2 回パスするという別の方法を検討してください。
32 ビットの int がある場合、それを文字列に変換して、文字列の長さを調べる必要があります。リスト内のすべての項目に対して、変換を行うためのバッファーの割り当て、変換を行う時間、および文字列の割り当てを解除するための余分な時間を 1 回行います。int の長さの取得は、他のデータ型に比べて比較的簡単です。

複雑なオブジェクトについても検討してください。それらの長さを取得している場合、それらの表現は (おそらく) いくつかの.ToStringようなメソッドを呼び出すことによって構築されます。これは、すべてのサブオブジェクトToStringメソッドの結果を一緒に連結します。また、これを行うことになります。二回。

拡張可能な文字列バッファーをトスし、すべての文字列を 1 回余分に構築して長さを取得するとしたら? 私は毎回バッファに行きます。

于 2012-05-02T07:05:55.410 に答える
0

このバリアントsprintf()asprintf()、結果の文字列を格納するためのスペースを malloc します。事前に長さを知る必要はありません。

ほとんどのプラットフォームで C stdlib の一部として利用できます。詳細については (おそらく) を使用するman asprintf、マンページのこのオンライン コピーを参照してください。:

マニュアルページから:

関数の printf() ファミリは、以下で説明する形式に従って出力を生成します。printf() および vprintf() 関数は、標準出力ストリームである stdout に出力を書き込みます。fprintf() および vfprintf() は、指定された出力ストリームに出力を書き込みます。dprintf() および vdprintf() は、指定されたファイル記述子に出力を書き込みます。sprintf()、snprintf()、vsprintf()、および vsnprintf() は、文字列 s に書き込みます。asprintf() と vasprintf() は、malloc(3) で新しい文字列を動的に割り当てます。

追加:

asprintf() および vasprintf() 関数は、*ret を、フォーマットされた文字列を保持するのに十分な大きさのバッファへのポインタに設定します。このポインタは、不要になったときに割り当てられたストレージを解放するために、free(3) に渡す必要があります。十分なスペースを割り当てることができない場合、asprintf() と vasprintf() は -1 を返し、ret を NULL ポインタに設定します。

(強調のために太字を追加)

使用例を次に示します。

char *buffer;
asprintf(buffer, "Hello %s", myunknownlengthstring);

これにより、結果の書式設定された文字列を格納し、それを に格納するのに十分なスペースが割り当てられ&bufferます。このメモリを解放する責任があります。そうしないとリークfree(buffer)します。文字列が不要になったときの単純な方法で十分です。

于 2012-05-02T07:05:49.530 に答える