質問に対する直接の回答
私はロバートの答えが好きですが、私が提起した質問についてもいくつかの見解があります.
TR24731-1 関数をサポートするライブラリまたはコンパイラを使用していますか?
いいえ、私はしません。
もしそうなら、どのコンパイラまたはライブラリで、どのプラットフォームで使用されていますか?
関数は MS Visual Studio (MS VC++ 2008 Edition など) によって提供されていると思いますが、それらを使用するように促す警告があります。
これらの関数を使用するようにコードを修正した結果、バグが見つかりましたか?
まだ。そして、私のコードで多くのことが明らかになるとは思っていません。私が扱っている他のコードのいくつか - 多分。しかし、私はまだ確信していません。
最も価値のある機能はどれですか?
%n
関数の printf_s() ファミリーが「 」形式指定子を受け入れないという事実が気に入っています。
値がない、または負の値を提供するものはありますか?
tmpfile_s()
関数と関数はtmpnam_s()
ひどい失望です。mkstemp()
彼らは、TOCTOU (チェック時、使用時) の脆弱性がないことを確認するために、ファイルを作成して開くのと同じように機能する必要がありました。現状では、これら 2 つはほとんど価値がありません。
strerrorlen_s()
また、それはほとんど価値を提供しないと思います。
今後図書館を利用する予定はありますか?
私はそれについて2つの考えを持っています。標準 C ライブラリに TR 24731 の機能を実装するライブラリの作業を開始しましたが、正しく動作していることを実証するために必要な単体テストの量に悩まされました。それを続けるかどうかはわかりません。Windows に移植したいコードがいくつかあります (主に、すべてのプラットフォームでサポートを提供したいというひねくれた欲求からです。これは、数十年にわたって Unix 派生物に取り組んできました)。残念ながら、MSVC コンパイラからの警告なしにコンパイルするには、完全に信頼できる (慎重に使用した場合) 標準 C ライブラリ関数を使用して、MSVC が私のことを気にしないようにコードを塗りつぶす必要があります。そして、それは食欲をそそるものではありません。その期間に開発された 20 年分のシステムのほとんどに対処しなければならないのは十分に悪いことです。誰かの楽しみのアイデア (必要のないときに TR 24731 を採用させること) に対処しなければならないのは面倒です。それが、私がライブラリの開発を始めた理由の 1 つです。Unix と Windows で同じインターフェイスを使用できるようにするためです。でも、ここからどうなるかわかりません。
TR24731-2 の作業を追跡していますか?
質問のデータを収集しているときに標準サイトに行くまで、私はそれを追跡していませんでした. asprintf()
andvasprintf()
関数はおそらく価値があります。私はそれらを使用します。メモリ ストリーム I/O 関数についてはよくわかりません。Cstrdup()
レベルで標準化されたことは、大きな前進です。これは、パート 1 (境界チェック) インターフェースほど議論の余地がないように思えます。
全体として、パート 1 の「境界チェック インターフェイス」には納得できません。第 2 部「動的割り当て関数」のドラフトの資料の方が優れています。
それが私に任されていれば、パート 1 の行に沿って移動しますchar *
が、文字列の先頭に a を返す C99 標準 C ライブラリのインターフェイス (たとえばstrcpy()
and strcat()
) を修正して、代わりに先頭へのポインターを返すと、新しい文字列の末尾にある null バイトへのポインターが返されます。これにより、いくつかの一般的なイディオム (文字列を別の文字列の末尾に繰り返し連結するなど) がより効率的になりますstrcat()
。TR24731 バージョンのように、置換はすべて出力文字列のヌル終了を保証します。私は、インターフェイスのチェックや例外処理関数の考え方を完全に否定しているわけではありません。それはトリッキーなビジネスです。
Microsoft の実装は標準仕様と同じではありません
更新 (2011-05-08)
この質問も参照してください。悲しいことに、TR24731 関数の有用性にとって致命的なことですが、一部の関数の定義は、Microsoft の実装と標準の間で異なり、(私にとっては) 役に立たないものになっています。そこでの私の答えはvsnprintf_s()
.
たとえば、TR 24731-1 には、次のインターフェイスがvsnprintf_s()
あると記載されています。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
const char * restrict format, va_list arg);
残念ながら、MSDNによると、インターフェイスvsnprintf_s()
は次のとおりです。
int vsnprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format,
va_list argptr
);
パラメーター
- buffer - 出力の保存場所。
- sizeOfBuffer - 出力用のバッファーのサイズ。
- count - 書き込む最大文字数 (終端の null を含まない)、または _TRUNCATE。
- format - フォーマット仕様。
- argptr - 引数のリストへのポインター。
これは単に型マッピングの問題ではないことに注意してください。固定引数の数が異なるため、相容れません。また、'sizeOfBuffer' と 'count' の両方を使用することのメリットは、私には (おそらく標準化委員会にも) 不明です。同じ情報が 2 回あるように見えます (または、少なくとも、コードは通常、両方のパラメーターに同じ値で記述されます)。
scanf_s()
同様に、およびその親戚 にも問題があります。Microsoftは、バッファー長パラメーターの型は(「サイズ パラメーターの型は 」ではなく、 「 unsigned
」と明示的に述べています) と述べています。対照的に、附属書 K では、サイズ パラメータは型であり、これは(の別の名前ですが、より小さい)の制限されたバリアントです。したがって、 Microsoft C と標準 Cでは、コード呼び出しを別の方法で記述する必要があります。unsigned
size_t
rsize_t
size_t
rsize_t
size_t
RSIZE_MAX
SIZE_MAX
scanf_s()
当初、条件付きコードを記述する必要なく、Windows と Unix でコードをクリーンにコンパイルする方法として、「安全な」関数を使用することを計画していました。Microsoft と ISO の機能が常に同じであるとは限らないため、これは失敗するので、あきらめるにはかなり時間がかかります。
vsnprintf()
Visual Studio 2015における Microsoft の変更点
の Visual Studio 2015 ドキュメントではvsnprintf()
、インターフェイスが変更されたことに注意してください。
Visual Studio 2015 および Windows 10 の UCRT 以降、vsnprintf
は と同一ではなくなりました_vsnprintf
。このvsnprintf
関数は C99 標準に準拠しています。_vnsprintf
下位互換性のために保持されています。
ただし、Microsoft のインターフェイスvsnprintf_s()
は変更されていません。
Microsoft と Annex K の違いのその他の例
の C11 標準バリアントはlocaltime_s()
、ISO/IEC 9899:2011 付属書 K.3.8.2.4 で次のように定義されています。
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
localtime_s()
次のように定義された MSDN バリアントと比較して:
errno_t localtime_s(struct tm* _tm, const time_t *time);
localtime_r()
および次のように定義された POSIX バリアント:
struct tm *localtime_r(const time_t *restrict timer,
struct tm *restrict result);
C11 標準と POSIX 関数は、名前を除いて同等です。Microsoft 関数は、C11 標準と名前を共有していますが、インターフェイスが異なります。
違いのもう 1 つの例は、Microsoftstrtok_s()
と Annex Kstrtok_s()
です。
char *strtok_s(char *strToken, const char *strDelimit, char **context);
対:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
Microsoft バリアントには 3 つの引数があるのに対し、Annex K バリアントには 4 つの引数があることに注意してください。これは、Microsoft の引数リストがstrtok_s()
POSIX のものと互換性があることを意味しますstrtok_r()
— したがって、関数名を (例えばマクロによって) 変更すると、これらの呼び出しは事実上交換可能になります — しかし、標準 C (附属書 K) バージョンは、追加の引数で両方とは異なります。
Mac と Linuxでの宣言が異なるqsort_r()
という質問には、 qsort_s()
Microsoft によってqsort_s()
定義されたものと TR24731-1 によって定義されたものについても議論されている回答があります — 繰り返しますが、インターフェイスは異なります。
ISO/IEC 9899:2011 — C11 規格
C11 標準 ( 2010 年 12 月の草案。最終的な標準ISO/IEC 9899:2011の PDF コピーを ANSI Web ストアから 30 米ドルで一度に入手できます) には、TR24731-1 機能がオプションとして含まれています。規格の一部。それらは、「情報」ではなく「規範」である附属書 K (境界チェック インターフェース) で定義されていますが、オプションです。
C11 標準には、TR24731-2 関数が含まれていませんvasprintf()
。関数とその関連関数が本当に役立つ可能性があるため、これは悲しいことです。
簡単な要約:
- C11 には TR24731-1 が含まれています
- C11 には TR24731-2 が含まれていません
- C18 は TR24731 に関する C11 と同じです。
C11の後継から附属書Kを削除する提案
Deduplicatorは、別の質問へのコメントで、ISO C 標準委員会 (ISO/IEC JTC1/SC22/WG14) の前に提案があると指摘しました。
これには、附属書 K 関数の現存する実装の一部への参照が含まれています — それらはどれも広く使用されていません (ただし、興味がある場合はドキュメントから見つけることができます)。
ドキュメントは次の推奨事項で終わります。
したがって、附属書 K を C 標準の次の改訂版から削除するか、非推奨にしてから削除することを提案します。
私はその勧告を支持します。
C18 規格は、附属書 K のステータスを変更しませんでした。附属書 K を完全に削除するのではなく、欠陥を修復して、いくつかの変更を行うことを提唱する論文N2336があります。