10

VS2010 で正確に 4294967295 バイトのファイルを開くと、seekg 関数が正しく動作しないことがわかりました。

私は単純なコードを使用しています:

#include <iostream>
#include <fstream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    std::ifstream file;

    // cmd: fsutil file createnew tmp.txt 4294967295
    file.open(L"c:/tmp.txt", ifstream::in | ifstream::binary);

    if(!file.is_open())
        return -1;

    file.seekg(0, std::ios::end);

    auto state = file.rdstate();

    // this condition shoots only when size of the file is equal to 4294967295
    if((state & ifstream::failbit)==ifstream::failbit)
    {
        std::cout << "seekg failed";
    }

    // after seekg failed, tellg returns 0
    std::streampos endPos = file.tellg();

    return 0;
}

4294967294 と 4294967296 のファイルを使用した同じコードは問題なく動作しています。

誰かがこの問題の解決策を知っていますか?

アップデート:

その問題はここにあるようです:

template<class _Statetype>
class fpos
{
 __CLR_OR_THIS_CALL operator streamoff() const
 { // return offset
 return ((streamoff)(_Myoff + _FPOSOFF(_Fpos)));
 }
}

正確に

_FPOSOFF(_Fpos)

どこ

#define _FPOSOFF(fp) ((long)(fp))

したがって、 4294967295 を取り、それを -1 に変換します!

つまり、そのようなコードは失敗します

//returns -1, even if sizeof(fpos_t)=8
fpos_t pos = _FPOSOFF(4294967295);

_Myoff、_Fpos、streamoffset は 64 ビットです

すべての型が 64 ビットであるのに、なぜこの変換を行うのでしょうか!? 何も思いつきません ))

4

3 に答える 3

7

内部的に、ストリームの実装には、シークが失敗したときに返される 0xffffffff に等しい const '_BADOFF' があります。この場合、シークは成功していますが、シークからの戻り値が失敗コードと同じであるため、ストリーム ラッパーがその失敗コードを誤って設定することになります。

_BADOFF は 64 ビット型として定義されており、愚かな値が割り当てられています。

回避策として、1 バイト short をシークしてから、1 バイトを読み取ることができます。

file.seekg(-1, std::ios::end);
char temp; file >> temp;

ただし、このバグは特定のファイル オフセットがシークされるたびに発生するため、大きなファイルをランダムな場所にシーク​​すると問題が発生する可能性があることに注意してください。たとえば、ファイルが 1 バイト大きかった場合、この -1 シークは失敗するため、これは一般的な解決策ではありません。

OPは質問を拡張したので、回答を拡張します。はい、比較の前に安全でない変換を使用してシーク値がキャストされます。これは、エラー値との比較にのみ使用されるため、ファイル内のそのポイントを超えてシークする機能には影響しないようです-ストリームにはまだ正しいオフセットがあります。ただし、ソースで _BADOFF が「-1」に設定されており、同じ変換を受けて 0xffffffff に切り捨てられるため、そもそも _BADOFF が疑わしい根本的な原因であるように思われます。

そのため、ライブラリの修正はキャストを修正することかもしれません (そうすることによる他の副作用がないことを前提としています) が、問題を回避するために、下位 32 ビットが設定されています。私が見ることができるものから、それはOKを超えて探します。

于 2012-12-12T11:51:18.427 に答える
5

これは確かに Visual C++ 2010 のバグですstd::fstream。Microsoft Connect で 2 年前に報告されまし 。で_FPOSOFF)。

このバグは、_FPOSOFF次のように定義されている Visual C++ 2012 で修正されています。

#define _FPOSOFF(fp)  ((long long)(fp))

可能であれば、Visual C++ 2012 にアップグレードすることをお勧めします。

于 2012-12-12T18:41:32.590 に答える
2

現時点では、あまり良くない解決策が 2 つあります。

  1. stdio.h を修正する

    #define _FPOSOFF(fp) ((long long)(fp))

  2. VS2012に移行(これも悲しい)

    これはバグであり、Visual Studio 2012 で修正されています。_FPOSOFF は long long にキャストされるようになり、切り捨てが回避されます。– ジェームズ・マクネリス

于 2012-12-12T18:43:42.387 に答える