C ++標準がファイルを処理する方法を模索するのはなぜですか?


17

C ++は、streamoffタイプを使用して(ファイル)ストリーム内のオフセットを表し、[stream.types]で次のように定義されます。

using streamoff = implementation-defined ;

タイプstreamoffは、オペレーティングシステムの最大可能ファイルサイズを表すのに十分なサイズの、署名された基本的な整数型の1つの同義語です。287)

287)通常は長いです。

これは、(long32ビット幅しかない可能性があるを使用するのとは対照的に)大きなファイル内をシークできるため、理にかなっています。

[filebuf.virtuals]はbasic_filebuf、ファイル内でシークする関数を次のように定義します。

pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;

off_typestreamoffはと同等です。[iostreams.limits.pos]を参照してください。ただし、標準は、関数の効果を説明し続けます。私は最後の文にイライラしていますfseek

効果:レッツをwidth示しますa_codecvt.encoding()is_open() == false、またはの場合、off != 0 && width <= 0位置決め操作は失敗します。それ以外の場合、way != basic_ios::curまたはoff != 0、および最後の操作が出力された場合は、出力シーケンスを更新し、シフト解除シーケンスを書き込みます。次は、新しい位置をシーク:場合はwidth > 0、呼び出しfseek(file, width * off, whence)、そうでない場合は呼び出しますfseek(file, 0, whence)

fseeklongパラメータを受け入れます。off_typestreamoff定義されている場合long long(標準で推奨されているとおり)、これはlong呼び出し時にへのダウンコンバージョンにfseek(file, width * off, whence)つながる可能性があります(バグの診断が困難になる可能性があります)。これはstreamoff、そもそも型を導入する根拠全体に疑問を投げかけます。

これは意図的なものですか、それとも規格の欠陥ですか?


8
欠陥は次のようになります。
Yakk-Adam Nevraumont

gcc libstdc ++がfseeko64を使用しているようです。
KamilCuk

1
手の込んだ、それはseekoff必ずしもフードの下で使用 fseekするようには見えません。むしろ、(おそらくおなじみ?)の動作は、fseekseekoffをしているのかを説明するために使用されます。
jjramsey

@jjramseyこれも私の印象でした。ただし、その言い方は説明ではなく要件を示唆しているようです。
jceed2

1
@jjramsey「Effects」の部分はfseek、同じ効果を持つ何かを実行する限り、実際に呼び出す必要がないことを意味すると合理的に解釈できることに同意します。ただしfseek、オフセットが以下LONG_MINまたはそれ以上の場合LONG_MAXは効果がないため、少なくともがより大きい実装でstreamoffは、説明はせいぜい不完全ですlong
キース・トンプソン、

回答:


6

あなたがこれから描いている、C ++ストリーム間に不一致があり、それがfseekランタイムバグにつながるという結論は正しくないと思います。状況は次のようです:

  1. longが64ビットのシステムでは、streamoffはとして定義されlongseekoff関数はを呼び出しますfseek

  2. ここで、システム上でlong32ビットが、OSがサポートする64ビット・ファイル・オフセットであり、streamoffとして定義され、long longそしてseekoffいずれか呼び出された関数呼び出しfseekoまたはfseeko6464ビットのオフセットを受け付けます。

これseekoffが私のLinuxシステムの定義からの抜粋です。

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFSはLarge File Supportの略です。

結論:標準では、streamoffそのseekoff呼び出しの要件と表面的に矛盾する定義が提案されていますがfseek、ライブラリ設計者fseekは、OSがサポートするオフセットの全範囲を受け入れるのバリアントを呼び出す必要があることを理解しています。


@ypnos反対票を投じなかったので、この回答は役に立ちました。ポイントを逃したので誰かが反対票を投じたと思います。問題は、この点で標準を無視する正常な実装があることではなく、問題は、実装を正常にするために標準を無視する必要があることです。
jceed2

6
The situation seems to be:-実装が呼び出さfseekれないように許可されていない状況ですseekoff。呼び出す必要がありますがfseek、呼び出しません標準はそれをする言います。この実装は無効であると私は主張できます。私はそれが質問に答えないと信じています。OCH、見つかったLLVM、それが呼び出されますfseeko
KamilCuk

参考までに、VC ++は_fseeki64この関数を呼び出します。これも基準が言うことに違反しているようです。
ChrisMM

1
これは、実装者が問題を認識し、標準を無視する場合です。私は彼らがそうしたのは嬉しいですが、標準は本当に修正される必要があります。
NathanOliver

1
一部の人々は、文字通り標準も取り入れています。実装が文字通りと呼ばれる関数を呼び出すことを要求していませんfseek。他の場所では、標準は何かを「を呼び出すかのように」と説明していfseek(...)ます。それが文字通りの呼び出しについてそんなに気にかけたならfseek、そのステートメントは異なります。真剣に、C ++ライブラリを実装している場合はどうしますか?fseekドキュメントで指示されているため、64ビットファイルオフセットの下位32ビットで呼び出しを要求しますか?あなたの顧客はそれをありがとうでしょうか?
ウィリスブラックバーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.