0

私はいくつかのレガシーコードを使用しています。次のシナリオでは、レガシーコードは本番モードで機能します。テスト目的で、レガシーコードのコマンドラインバージョンを作成しようとしています。ここでは環境設定の問題があると思いますが、私はC++とVisualStudio(長年のEclipse / Javaの人)には比較的慣れていません。

このコードは、ストリームから文字列を読み込もうとしています。簡単に読み取ると、私のデバッグシナリオでは値が11になります。次に、11文字で読み取ることになっています。しかし、このコードは最初の文字をクラップスします。具体的には、read以下のメソッドでは、ptrがnullであるため、fread呼び出しは例外をスローしています。なぜptrNULLなのですか?

明確化のポイントはptr、operator >>(string)呼び出しとoperator >>(char)呼び出しの間でnullになります。

Mystream& Mystream::operator>>( string& str )
{
string::iterator                it;
short                           length;

*this >> length;

if( length >= 0 )
{
    str.resize( length );
    for ( it = str.begin(); it != str.end(); ++it )
    {
        *this >> *it;
    }
}

return *this;
}

ショートを読み取る方法はここにあり、ファイルバッファなどを確認します。これは正常に機能しているように見えます。

Mystream& Mystream::operator>>(short& n )
{
    read( ( char* )&n, sizeof( n ) );
    SwapBytes( *this, ( char* )&n, sizeof( n ) );
    return *this;
}

さて、charを読み取る方法は次のとおりです。

Mystream& Mystream::operator>>(char& n )
{
    read( ( char* )&n, sizeof( n ) );
    return *this;
}

読み取りメソッドは次のとおりです。

Mystream& Mystream::read( char* ptr, int n )
{
fread( (void*)ptr, (size_t)1, (size_t)n, fp );
return *this;
} 

私が理解していないことの1つは、文字列入力メソッドで、*それは文字ですよね?では、なぜoperator >>(char&n)メソッドがその行にディスパッチされるのでしょうか。デバッガーでは、*それは0のように見えます(同僚はそのようなことで2005デバッガーを信頼していないと言っていますが)、したがって、&nはnullポインターとして扱われるように見えるので、メソッドは例外をスローしています。

あなたが提供できる洞察は最も役に立ちます!

ありがとうジョン

ps。不思議なことに、SwapBytesは次のようになります。

inline void SwapBytes( Mystream& bfs, char * ptr, int nbyte, int nelem = 1)
{ 
    // do we need to swap bytes?
if( bfs.byteOrder() != SYSBYTEORDER )
    DoSwapBytesReally( bfs, ptr, nbyte, nelem );
}

そしてDoSwapBytesReally次のようになります:

void DoSwapBytesReally( Mystream& bfs, char * ptr, int nbyte, int nelem )
{
    // if the byte order of the file
    // does not match the system byte order
    // then the bytes should be swapped
int i, n;
char temp;

#ifndef _DOSPOINTERS_
char *ptr1, *ptr2;
#else _DOSPOINTERS_
char huge *ptr1, huge *ptr2;
#endif _DOSPOINTERS_

int nbyte2;

nbyte2 = nbyte/2;

for ( n = 0; n < nelem; n++ ) 
{
    ptr1 = ptr;
    ptr2 = ptr1 + nbyte - 1;

    for ( i = 0; i < nbyte2; i++ ) 
    {
        temp = *ptr1;
        *ptr1++ = *ptr2;
        *ptr2-- = temp;
    }

    ptr += nbyte;
}
}
4

2 に答える 2

2

私はこの混乱を捨てて、最初からやり直します。コードから推定すると、実際に機能した場合、次のようなものとほぼ同等になります。

MyStream::operator>>(string &s) { 
    short size;

    fread((void *)&size, sizeof(size), 1, fP);
    size = ntohs(size); // oops: after reading edited question, this is really wrong.
    s.resize(size);
    fread((void *)&s[0], 1, size, fp);
    return *this;
}

この場合、ほとんどの作業を他の関数に委譲してもあまり効果がないように思われます。これは作業をより直接的に行いますが、元の作業よりも大幅に長くも複雑でもありません (どちらかといえば、むしろ反対)。

于 2012-08-03T16:18:34.417 に答える
0

会社で、私に何が起こっているのかを説明できる灰色のひげを見つけました。(私はすでに 2 人の古いタイマーと話していたので、古いタイマーの攻撃経路をカバーしたと考えました。) 上記のコードは ANSI 準拠の STL コードではありません。Visual Studio 2005 で、Microsoft は最初に STL を導入しましたが、問題がありました。特に、以前は機能していた古いコードは 2005 年には機能しなくなります (これには 64 ビット モードも関与している可能性があります)。このため、コードはデバッグ モードでは機能しません (ただし、リリース モードでは機能します)。部分的な記事の 1 つがここにあります。 http://msdn.microsoft.com/en-us/library/aa985982%28v=vs.80%29.aspx

私が見た特定の問題は it = str.begin()、質問の最初の方法の行に関係しています。 str空文字列です。したがってstr.begin()、技術的には定義されていません。Visual Studio は、この状況をデバッグ モードとリリース モードで異なる方法で扱います。(これはデバッグでは実行できません。リリースでは実行できます。)

要するに、灰色のあごひげは、書き換えがまさにジェリーのものであることを示唆していました。皮肉なことに、灰色のひげはいくつかのファイルでこの問題を修正していましたが、メインラインにチェックインすることを怠っていました。ええとああ。それは &#$!! を怖がらせます。私から。

于 2012-08-03T18:16:08.560 に答える