いわゆる安全なライブラリの deprecations について尋ねた以前の質問の型では、なぜfopen()
deprecated にする必要があるのか について同様に困惑しています。
この関数は 2 つの C 文字列を取り、FILE* ptr を返すか、失敗すると NULL を返します。スレッドセーフの問題/文字列オーバーランの問題はどこにありますか? それとも別のものですか?
前もって感謝します
いわゆる安全なライブラリの deprecations について尋ねた以前の質問の型では、なぜfopen()
deprecated にする必要があるのか について同様に困惑しています。
この関数は 2 つの C 文字列を取り、FILE* ptr を返すか、失敗すると NULL を返します。スレッドセーフの問題/文字列オーバーランの問題はどこにありますか? それとも別のものですか?
前もって感謝します
使用できますfopen()
。まじめな話、ここで Microsoft に注意しないでください。Microsoft は、ISO 標準から逸脱することで、プログラマーに真の不利益をもたらしています。彼らは、コードを書いている人はどういうわけか頭が死んでいて、ライブラリ関数を呼び出す前にパラメーターをチェックする方法を知らないと考えているようです.
C プログラミングの複雑さを学ぼうとしない人は、実際にそれを行う必要はありません。彼らはより安全な言語に移行する必要があります。
これは、Microsoft による開発者のベンダー ロックインのもう 1 つの試みのようです (ただし、それを試みているのは彼らだけではないので、特に彼らを非難しているわけではありません)。私は通常追加します:
#define _CRT_SECURE_NO_WARNINGS
(または"-D"
コマンドラインのバリアント)をほとんどのプロジェクトに追加して、完全に有効で合法的なCコードを作成するときにコンパイラーに煩わされないようにします。
Microsoft は、関数に追加機能fopen_s()
(ファイル エンコーディングなど) を提供し、返される方法を変更しました。これにより、Windows プログラマーにとっては改善されるかもしれませんが、コードは本質的に移植できなくなります。
Windows 用のコードだけを作成する場合は、ぜひ使用してください。私自身は、自分のコードをどこでもコンパイルして実行できることを好みます (できるだけ変更を加えずに)。
C11 の時点で、これらのセーフ関数は標準の一部になりましたが、オプションです。詳細については、附属書 K を参照してください。
公式のISO/IEC JTC1 / SC22 / WG14(C言語)テクニカルレポートTR24731-1(境界チェックインターフェイス)とその理論的根拠は次の場所で入手できます。
TR24731-2(動的割り当て機能)に向けた作業もあります。
述べられている理論的根拠fopen_s()
は次のとおりです。
6.5.2ファイルアクセス機能
ファイルを作成するとき、
fopen_s
andfreopen_s
関数は、ファイル保護を設定し、排他的アクセスでファイルを開くことにより、不正アクセスからファイルを保護することにより、セキュリティを向上させます。
仕様によると:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
errno_t fopen_s(FILE * restrict * restrict streamptr,
const char * restrict filename,
const char * restrict mode);
、、、またはstreamptr
のいずれもnullポインタにはなりません。filename
mode
実行時制約違反がある場合はfopen_s
、ファイルを開こうとしないでください。さらに、streamptr
がnullポインタでない場合は、nullポインタにfopen_s
設定*streamptr
します。
この
fopen_s
関数は、が指す文字列を名前とするファイルを開き、filename
ストリームを関連付けます。モード文字列は、の説明どおりである必要が
fopen
あります。さらに、文字「w」または「a」で始まるモードの前に文字「u」を付けることができます。以下を参照してください。
uw
長さをゼロに切り捨てるか、書き込み用のテキストファイルを作成します。デフォルトの権限ua
追加; ファイルの終わりに書き込むためのテキストファイルを開くか作成します。デフォルトの権限uwb
長さをゼロに切り捨てるか、書き込み用のバイナリファイルを作成します。デフォルトの権限uab
追加; ファイルの終わりに書き込むためのバイナリファイルを開くか作成します。デフォルトの権限uw+
長さをゼロに切り捨てるか、更新用のテキストファイルを作成します。デフォルトの権限ua+
追加; 更新用のテキストファイルを開くか作成し、ファイルの終わりに書き込み、デフォルトの権限uw+b
またはuwb+
長さをゼロに切り捨てるか、更新用のバイナリファイルを作成します。デフォルトの権限ua+b
またはuab+
追加; 更新用のバイナリファイルを開くか作成し、ファイルの終わりに書き込み、デフォルトの権限基盤となるシステムが概念をサポートしている限り、書き込み用に開かれたファイルは、排他的(非共有とも呼ばれる)アクセスで開かれるものとします。ファイルが作成されていて、モード文字列の最初の文字が「u」でない場合、基盤となるシステムがサポートしている範囲で、ファイルには、システム上の他のユーザーがファイルにアクセスできないようにするファイル権限が必要です。ファイルが作成されていて、モード文字列の最初の文字が「u」の場合、ファイルが閉じられるまでに、システムのデフォルトのファイルアクセス許可が付与されます10)。
ファイルが正常に開かれた場合、が指すポインタ
FILE
はstreamptr
、開かれたファイルを制御するオブジェクトへのポインタに設定されます。それ以外の場合、が指すポインタはnullポインタに設定されますFILE
。streamptr
戻り値
fopen_s
ファイルを開いた場合、関数はゼロを返します。ファイルを開かなかった場合、または実行時制約違反があった場合は、fopen_s
ゼロ以外の値を返します。10)これらは、ファイルがfopenによって作成された場合と同じ権限です。
このfopen_s()
関数は Microsoft によって C ランタイムに追加されましたが、次の基本的な違いがありますfopen()
。
基本的に、アプリケーションが書き込むファイルはデフォルトで他のユーザーから保護されていることを意味します。
fopen()
既存のコードが壊れる可能性があるため、彼らはこれをしませんでした。
Microsoft はfopen()
、Windows の開発者に、アプリケーションが使用するファイルのアクセス許可が緩くなるかどうかについて意識的な決定を下すことを奨励するために、非推奨にすることを選択しました。
Jonathan Leffler の回答は、提案された標準化言語を提供しますfopen_s()
。根拠を明確にするために、この回答を追加しました。
それとも別のものですか?
「fopen」で使用される FILE 構造の一部の実装では、「unsigned short」として定義されたファイル記述子があります。これにより、stdin、stdout、および stderr を除いて、最大 255 の同時オープン ファイルが残ります。
もちろん、255 個のオープン ファイルを持つことができることの価値については議論の余地がありますが、この実装の詳細は、Solaris 8 プラットフォームで252個を超えるソケット接続がある場合に具体化されます。私のアプリケーションで libcurl を使用して SSL 接続を確立する際にランダムに失敗したように最初に見えたのは、これが原因であることが判明しました。
'fopen' のすべてが悪いわけではありませんが、古いインターフェイスの束縛を捨てることの美徳を見ることができます。非推奨の選択は、時代遅れの実装とのバイナリ互換性を維持するという苦痛に基づいている可能性があります。
スレッドセーフ。fopen()
はグローバル変数 を使用しますがerrno
、fopen_s()
置換は を返し、ファイル ポインタを格納errno_t
する引数を取ります。FILE**
新しいバージョンはパラメーターの検証を行いますが、古いバージョンはそうではありませんでした。
詳細については、この SO スレッドを参照してください。