インタビュー中に、(とりわけ) 次の機能を実装するように要求されました。
int StrPrintF(char **psz, const char *szFmt, ...);
に似てsprintf
いますが、既に割り当てられているストレージの代わりに、関数がそれ自体を割り当て、*psz
変数に返す必要があることを除きます。さらに、*psz
すでに割り当てられている (ヒープ上にある) 文字列を指している可能性があり、これはフォーマット中に使用される可能性があります。当然、この文字列は適切な手段で解放する必要があります。
戻り値は、新しく作成された文字列の長さ、またはエラーの場合は負になります。
これは私の実装です:
int StrPrintF(char **psz, const char *szFmt, ...)
{
va_list args;
int nLen;
va_start(args, szFmt);
if ((nLen = vsnprintf(NULL, 0, szFmt, args)) >= 0)
{
char *szRes = (char*) malloc(nLen + 1);
if (szRes)
if (vsnprintf(szRes, nLen + 1, szFmt, args) == nLen)
{
free(*psz);
*psz = szRes;
}
else
{
free(szRes);
nLen = -1;
}
else
nLen = -1;
}
va_end(args);
return nLen;
}
質問の作成者は、この実装にはバグがあると主張しています。特定の難解なシステムで失敗する可能性のある標準的な違反だけでなく、偶然にもほとんどのシステムで失敗する可能性がある「実際の」バグです。
またはint
などのメモリ機能に適した型の代わりに を使用することにも関係しません。たとえば、文字列は「妥当な」サイズです。size_t
ptrdiff_t
バグが何であるかは本当にわかりません。すべてのポインター演算は問題ありません。を 2 回呼び出しvsnprintf
ても同じ結果が得られるとは思いもしません。すべての可変引数処理も正しい IMHO です。va_copy
は必要ありません ( を使用する呼び出し先の責任ですva_list
)。また、x86 では意味がva_copy
ありません。va_end
誰かが (潜在的な) バグを発見できれば幸いです。
編集:
回答とコメントを確認した後、メモを追加したいと思います。
- 当然のことながら、変数の状態を監視しながら、デバッガーでのステップバイステップなど、さまざまな入力を使用してコードをビルドして実行しました。最初に自分で試してみずに助けを求めることはありません。問題の兆候、スタック/ヒープの破損などは見られませんでした。また、デバッグ ヒープを有効にしてデバッグ ビルドで実行しました (これはヒープの破損に耐えられません)。
- 関数は有効なパラメーターで呼び出されると仮定します。つまり
psz
、有効なポインター ( と混同しないでください*psz
) でszFmt
あり、有効な書式指定子であり、すべての可変引数が評価され、書式文字列に対応します。 - ポインターでの呼び出し
free
はNULL
、標準に従って問題ありません。 - 呼び出し
vsnprintf
は、NULL
ポインターとサイズ = 0 で問題ありません。結果の文字列の長さを返す必要があります。MS バージョンは、完全に標準に準拠しているわけではありませんが、この特定のケースでは同じことを行います。 vsnprintf
0 ターミネータを含め、指定されたバッファ サイズを超えません。手段 - それは常にそれを配置するとは限りません。- コーディング スタイルは脇に置いておいてください (気に入らない場合は、問題ありません)。