2012-05-02 15 views
1

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

解説:私はErlangのC関数を書くことを考えています。 Erlangsのデータ型は深くボックス化されているので、asprintfのような関数を使うには、それらをすべてアンボックスする必要があります(そしておそらくはフォーマット文字列を書き直す必要があります)。

+0

使用している言語を指定すると役立ちます。 'printf()'は[いくつかのプリミティブ](http://en.wikipedia.org/wiki/Printf_format_string#Format_placeholders)のみを理解しています。あなた自身で書く場合を除いて、printfに任意の型を渡すことはできません。どうか明らかにしてください。 –

+0

@Beaks - もしあなたが 'printf("%s "、myString)'のようなことをして、あなたが割り当てた固定幅のバッファに書いているとすれば、どういう意味になるのですか? – ckhan

+0

@ si14:バッファに書き込む必要があるのはなぜですか? printfがストリームに書き込むと、呼び出し元が十分に大きいバッファをsprintfに渡します。 – ckhan

答えて

2

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

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

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

自分でロールバックした場合は、512バイトの妥当なバッファから始めます。この制限に達すると、別のバッファを前回の制限(前回の1024回、2048秒など)の2倍のに割り当て、バッファ1をバッファ2にコピーし、新しいバッファを古いものに置き換え、空き/削除/最初のバッファの割り当てを解除します。

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

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

更新
があるため再配置の準最適な解決策のように感じています。私が間違っている?

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

今すぐ検討してくださいあなたの代わりに、フォーマットされるアイテムを2回通過させます。
32ビット整数の場合は、文字列に変換して文字列の長さを調べる必要があります。リスト内のすべての項目に対して1つの余分な時間を費やすことになります。これは、変換を行うバッファ、変換を実行してから文字列の割り当てを解除する時間です。 intの長さを取得することは、他のいくつかのデータ型に比べて比較的簡単です。

複雑なオブジェクトも考えてみましょう。それらの長さを取得している場合は、.ToStringというメソッドを呼び出してその表現を構築します(すべてのサブオブジェクトToStringメソッドの結果を連結します)。あなたはこれを2回行うでしょう。

拡張可能な文字列バッファの間にトスがあり、すべての文字列を構築して長さを増やす余分な時間が1つありますか?私はいつもバッファーのために行くだろう。

+0

標準ライブラリにこれを行う関数が存在するため、OPが自分の高価な(mallocが非常に高価なシステムコールである)例外的な問題の劣った解決策を奨励することは賢明ではない。私は正解と信じていることを投稿しました。 (確かにOPがCを使用しているのかどうかは不明だが) –

+0

@Beaks: "OPに自分のロールを奨励する"。質問者は自分自身を転がすように勧めますか?彼はいくつかの(不特定の)**動的**言語でこれを実装しようとしています。私は彼が手にしなければならないツールやユーティリティは何も知らず、必要な場合には素人の骨のアプローチを概説しました。また、彼が標準ライブラリにアクセスできることをどのように知っていますか?メイト私は彼らが当然のところで私の舐めを取るだろうが、私は正直なところ、これがだとは思わない。 –

+0

@BinaryWorrierは、再割り当てのために最適以下のソリューションのように感じます。私が間違っている?あなたとビークス​​について話をすると、あなたは正しいと主張します。 – si14

0

という変形があります。asprintf()と呼ばれるこの変形では、長さを事前に知らなくても結果の文字列を格納する領域をmallocします。

それはCのSTDLIBの一環として、ほとんどのプラットフォームで利用可能です、あなたはman asprintfor at this online copy of the manpage.で(おそらく)詳細を読むことができます:

manページFromt:

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

追加:

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

(強調のために添加太字)

ここで少量の試料の使用は次のとおり

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

これは、結果のフォーマットされた文字列を格納し&bufferでそれを格納するのに十分なスペースを割り当てるべきです。あなたはこのメモリを解放する責任があります。それ以外の場合はリークしますが、文字列が不要になったときには単純なfree(buffer)で十分です。

+0

Askerは、これを**動的**言語で実装していると述べています。なぜあなたは標準のCライブラリについて語っていますか? –

+0

私はターゲット言語ですべての値をアンボックスする必要があるので、私はasprintfを使うことができません(私はErlangのC関数を書くことを考えていて、その値は時には深く囲まれています)。割り当てを解除することは非常にコストがかかるでしょう。 – si14

関連する問題