0

我正在使用一些遗留代码。在以下场景中,遗留代码在生产模式下工作。我正在尝试构建遗留代码的命令行版本以进行测试。我怀疑这里存在环境设置问题,但我对 C++ 和 Visual Studio 比较陌生(长期使用 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;
}

读取short的方法是here并查看文件缓冲区等。这看起来工作正常。

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

现在,读取字符的方法在这里:

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;
} 

有一件事我不明白,在字符串输入法中,*它是一个字符对吗?那么为什么 operator>>(char &n) 方法会在那一行被调度呢?在调试器中,它看起来像 *it 是一个 0,(尽管一位同事告诉我他不信任 2005 调试器在这些事情上),因此,看起来 &n 被视为空指针,因此读取方法抛出异常。

您可以提供的任何见解都将是最有帮助的!

谢谢约翰

附言。出于好奇,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 中,微软首先引入了 STL,但存在一些问题。特别是过去可以工作的旧代码现在在 2005 年会失败(我认为 64 位模式也可能在其中发挥作用。)因此,代码将无法在调试模式下工作(但它会在发布模式下工作)。一篇部分文章位于此处。 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 回答