如何找到`FILE *`的相对地址

时间:2014-10-24 05:14:26

标签: c++ c file ros

要了解我为何要执行下述操作,您可以阅读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

它显然有效,但它不是我试图实现的,因为在这种情况下,我将不得不自己解析数据,我试图避免。

1 个答案:

答案 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内部。这是个坏主意。它不仅不可移植,它可能会破坏任何随机编译器或标准库更新。它并没有解决你的问题。