【问题标题】:Random Bytes added to an end of a buffer添加到缓冲区末尾的随机字节
【发布时间】:2013-02-12 03:42:01
【问题描述】:

我正在从该类中重新创建一些 System.IO 函数。 当我设置一个缓冲区并分配 n 个字节时,它会读取字节,然后将随机字节添加到该缓冲区的末尾。

例如:

我的主要:

int main(int argc, char *args[])
{
    SetConsoleTitle(TEXT("Stream Test."));
    cout<<"Press any Key to begin reading.";
    cin.get();
    const char* data = File::ReadAllBytes(args[1]);
    Stream* stream = new Stream(data);
    char* magic = new char[8];
    stream->Read(magic, 0, 8);
    magic[8] = '\0';
    cout<<magic<<endl<<endl;
    delete[]data;
    cout<<"Press any key to quit.";
    cin.get();
    return 0;
}

这是我的 System::IO 命名空间 + 流类:

namespace System
{
    namespace IO
    {
        class File
        {
        public:
            static char* ReadAllBytes(const char *name)
            {
                ifstream fl(name, ifstream::in|ifstream::binary);
                fl.seekg( 0, ifstream::end );
                size_t len = fl.tellg();
                char* ret = new char[len+1];
                ret[len] = '\0';
                fl.seekg(0); 
                fl.read(ret, len);
                fl.close();
                return ret;
            }

            //not sure of this use yet.
            static size_t fileSize(const char* filename)
            {
                ifstream in(filename, ifstream::in | ifstream::binary);
                in.seekg(0, ifstream::end);
                return in.tellg(); 
            }
        };

        class Stream
        {
        public:
            const char *_buffer;
            __int64 _origin;
            __int64 _position;
            __int64 _length;
            __int64 _capacity;

            bool _expandable;
            bool _writable;
            bool _exposable;
            bool _isOpen;

            static const int MemStreamMaxLength = 2147483647;

            Stream()
            {
                InitializeInstanceFields();
            }

            Stream(const char *buffer)
            {
                _buffer = buffer;
                _length = strlen(_buffer);
                _capacity = _length;
                _position = 0;
                _origin = 0;
                _expandable = false;
                _writable = true;
                _exposable = true;
                _isOpen = true;
            }

            int ReadByte()
            {
                if (_position >= _length)
                    return -1;
                return _buffer[_position++];
            }

            void Read(char* &buffer, int offset, int length)
            {
                if((_position + offset + length) <= _length)
                {
                    memcpy( buffer, _buffer + (_position + offset), length );
                    _position += length;
                }
            }

            private:
                void InitializeInstanceFields()
                {
                    _origin = 0;
                    _position = 0;
                    _length = 0;
                    _capacity = 0;
                    _expandable = false;
                    _writable = false;
                    _exposable = false;
                    _isOpen = false;
                }
        };
    }
}

这就是最终发生的事情:

谁能解释为什么会发生这种情况,我该如何解决,或者其他什么?我是 C++ 新手,所以任何解释都会有所帮助。另外请不要批评我的脚本,我知道它可能很糟糕、过时、已弃用等,但我愿意学习,任何有帮助的建议都会变得更好。 :)

【问题讨论】:

  • 缺少空终止符? magic[7] = '\0';.
  • @JesseGood 我会试试的。
  • @JesseGood 哇,我在做 = '/0'!非常感谢,但你能解释一下为什么我必须首先这样做吗?我在某处读到,windows 并不总是分配你告诉它的 n 空间量或这些线周围的东西。
  • 它仍然会在文件中包含前 8 个字节,然后在没有空终止的情况下成为垃圾,对吗?
  • @user1425433:在 C++ 中,空终止符表示字符串的结尾。没有它,就无法知道您的字符串何时结束。在 C++ 中,跟踪数组的大小等必须由程序员完成,当您执行 cout &lt;&lt; magic 时,将打印字符直到达到空终止符。尽管您的数组只有 8 个chars,但通常您可以访问超出数组末尾的内存(尽管这在技术上是 UB),除非您遇到页面边界。与其他语言不同,访问超出数组末尾的内存是可能的,这些是您看到的随机字节。

标签: c++ stream unmanaged


【解决方案1】:

您只能在 C 风格的字符串上使用 operator &lt;&lt; (char *),而不是任意的字符数组。您如何期望它知道要输出多少个字符?

【讨论】:

  • @DavidSchwarts 这是一条评论
  • 我明白了,无论如何我只会在控制台中输出 C 字符串.. 但它不会知道: char* data = new char[8];你不是告诉它它将是一个 8 字节长的字符数组吗?我也应该使用 unsigned char 还是有关系?
  • @user1425433 不。帮自己一个忙,阅读一本关于 C++ 的,而不是假设您可以重用您的 C# 知识,因为它也以“C”开头。 C# 数组与 C++ 数组的唯一共同点是方括号。
  • @user1425433:您传递给operator &lt;&lt; 的只是char *——指向内存中某个地址的指针。如何从指向单个字符的指针中判断应该打印多少个字符?您确实将8 传递给operator new,但这只会给您返回char *
【解决方案2】:

我猜该文件没有正确打开,因此根本没有设置魔法缓冲区,这留下了初始化的垃圾数据:

如果构造函数没有成功打开文件,对象 尽管没有文件与流缓冲区关联,但仍会创建 并且设置了流的故障位(可以通过继承检查 会员失败)。 http://www.cplusplus.com/reference/fstream/ifstream/ifstream/

尝试在此过程中添加更多错误检查(使用 cout),尤其是在打开和读取缓冲区时。也许将魔术缓冲区设置为零或成功时被覆盖的可识别值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-28
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 2021-04-12
    • 2017-09-29
    • 2015-07-02
    相关资源
    最近更新 更多