要了解我为何要执行下述操作,您可以阅读this问题。简而言之:由于某种原因,库代码请求一个未由相应类定义的函数,我的解决方案是:通过我的自定义函数扩展类,编写所请求的函数并使用我的类。
我有一个函数void* advance(uint64_t nbytes)
,它会被某些库代码称为memcpy(object.advance(nbytes), source, nbytes)
。从advance()
里面我可以访问存储结果的FILE*
,所以根据我的理解,我必须返回一个指针,该指针将有一个相对于整个内存的地址,但是在{ {1}}以便库代码可以正确编写。
到目前为止我尝试过:
FILE*
由于我不熟悉文件的内存分配一般是如何工作的,所以我认为技术上也应该分配它,因此我这样做了:
void* advance(uint64_t nbytes){
return this->getFilePointer()->_IO_buf_base;
}
void* advance(uint64_t nbytes){
return this->getFilePointer()->_IO_write_base;
}
我在上一个例子中发现,由于某种原因void* advance(uint64_t nbytes){
char *ptr = new char [nbytes];
fwrite(ptr,1,nbytes,this->getFilePointer());
return this->getFilePointer()->_IO_write_base;
}
而this->getFilePointer()->_IO_write_ptr - this->getFilePointer()->_IO_write_base == 125
,因此显然有些错误......
以上所有示例都会触发段错误。
我的逻辑是否正确,即做我正在做的事情是否有意义?如果是,我怎样才能取得正确的结果?
P.S。我试图让问题尽可能短,如果需要任何其他信息,我会提供。
编辑:
这是调用nbytes == 9830525
advance()
void Bag::readMessageDataIntoStream(IndexEntry const& index_entry, Stream& stream) const {
ros::Header header;
uint32_t data_size;
uint32_t bytes_read;
switch (version_)
{
case 200:
{
decompressChunk(index_entry.chunk_pos);
readMessageDataHeaderFromBuffer(*current_buffer_, index_entry.offset, header, data_size, bytes_read);
if (data_size > 0)
memcpy(stream.advance(data_size), current_buffer_->getData() + index_entry.offset + bytes_read, data_size);
break;
}
case 102:
{
readMessageDataRecord102(index_entry.chunk_pos, header);
data_size = record_buffer_.getSize();
if (data_size > 0)
memcpy(stream.advance(data_size), record_buffer_.getData(), data_size);
break;
}
default:
throw BagFormatException((boost::format("Unhandled version: %1%") % version_).str());
}
}
将成为我的对象,它将继承自this一个
我也尝试了这个:
Stream
它显然有效,但它不是我试图实现的,因为在这种情况下,我将不得不自己解析数据,我试图避免。
答案 0 :(得分:4)
你的逻辑不正确,因为它打破了因果关系。
前两次尝试只是尝试覆盖一些FILE的内部数据,就是这样。他们没有,也不会触发写作。下一个在复制之前写入数据,然后尝试覆盖一些不相关的FILE内部数据(当然这将是段错误/ GPF)。
关键问题是首先调用函数,然后才复制数据(memcpy)。 memcpy不会单独触发文件写入。
您可以尝试以下方式:
advance()
的第一次调用只是分配一个缓冲区。每个后续调用首先尝试将缓冲区(在前一次advance()
调用之后立即填充)写入文件,然后为下一个缓冲区分配数据。最后,对象的析构函数(或者在完成复制操作后调用的某些方法,如果可以的话)从最后一次调用中分配的缓冲区中写入数据,然后(可选)关闭文件。即如下所示:
class AutoWrite {
public:
AutoWrite(FILE* file): file_(file), buffer_(nullptr), size_(0) {}
~AutoWrite() {
flush_last();
fclose(file_);
}
void* advance(uint64_t nbytes) {
flush_last();
buffer_ = new char[nbytes];
size_ = nbytes;
return buffer;
}
void flush_last() {
if (size_ > 0) {
fwrite(static_cast<void*>(buffer_), 1, size_, file);
size_ = 0;
delete[] buffer_;
}
}
private:
FILE* file_;
char* buffer_;
uint64_t size_;
};
事物有一个&#34;特征&#34;:数据不会立即保存,而是直接在分配下一个缓冲区之前(或在销毁对象期间)写入磁盘。 / p>
PS。不要搞乱FILE内部。这是个坏主意。它不仅不可移植,它可能会破坏任何随机编译器或标准库更新。它并没有解决你的问题。