【问题标题】:Getting FILE* in a safe C++ way以安全的 C++ 方式获取 FILE*
【发布时间】:2021-04-27 23:25:22
【问题描述】:

有没有办法以现代 C++ 方式获取已打开文件的 FILE* 句柄?...我想避免使用来自 <cstdlib>std::fopen,因为我被警告过它可能不安全。

我尝试检查是否有办法从fstream 检索FILE*,但似乎没有办法做到这一点。

【问题讨论】:

  • C++方式根本不涉及FILE*。
  • 所以没有办法在 C++ 中获取 FILE*?.. 因为仍然有一些函数甚至 boost 库可以利用它
  • 我很好奇您指的是什么函数,以及您所指的 boost 库是否已被标准库中的某些内容所取代。当然,您仍然可以使用 FILE*,但您将引入那些 C 标头来执行此操作。
  • FILE* 来自 C,而不是 C++。 C++ 处理文件的方式是改用std::(i|o)fstream
  • 回复:“警告说它可能不安全”——这有什么“不安全”的? C 程序员如何处理“不安全”?

标签: c++ c++17 file-handling


【解决方案1】:

一些乐趣。

namespace file {
  template<auto f>
  using constant = std::integral_constant< std::decay_t<decltype(f)>, f >;

  using file_ptr = std::unique_ptr<std::FILE, constant<std::fclose>>;

  FILE* unwrap( file_ptr const& ptr ) { return ptr.get(); }
  template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
  T&& unwrap( T&& t ) { return std::forward<T>(t); }
  file_ptr wrap( FILE* ptr ) { return file_ptr(ptr); }
  template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
  T&& wrap( T&& t ) { return std::forward<T>(t); }

  template<auto f>
  auto call = [](auto&&...args){ return wrap( f( unwrap(decltype(args)(args))... ) ); };
  // most FILE* operations can be rebound as follows:
  auto open = call<std::fopen>;
  auto close = call<std::fclose>;
  auto getc = call<std::fgetc>;
  auto putc = call<std::fputc>;
  // any one that works with raw buffers (like std::fread or std::fwrite) needs more work
}

其核心是unique_ptr&lt;FILE, thing that calls fclose&gt; 是一个质量不错的FILE* C++ 包装器。

然后我添加了一些机制,通过包装/解包将fgetc 和类似功能映射到在file::file_ptr 上运行的功能。

现在你可以这样做了:

auto pFile = file::open("hello.txt", "r");

Live example.

auto pFile = file::open("hello.txt", "r");
auto pFileOut = file::open("world.txt", "w");
if (pFile)
{
    while(auto c = file::getc(pFile))
    {
        file::putc(c, pFileOut);
    }
}

更高级的版本会从函数指针中获取参数,将它们扔到一个元组中,将它们映射到来自 munged 参数的元组。

所以

char*, int

将映射到std::span&lt;char&gt;

call 帮助器而不是上面的幼稚东西将采用 munged 参数,将它们映射到 C 样式参数的元组,将元组连接在一起,然后 std::apply C 函数。然后映射返回值。

call 稍加工作甚至可以有一个固定的签名而不是auto&amp;&amp;...,因此 IDE 可以给出提示。

【讨论】:

    【解决方案2】:

    我想避免使用&lt;cstdlib&gt; 中的std::fopen,因为有人警告我它可能不安全。

    fopen() 没有任何“不安全”之处。通过 C 标准,它是 C++ 标准的一部分。

    他们可能说的是使用 RAII 对象最好是管理资源(文件句柄),特别是如果您在程序中使用异常。

    我尝试检查是否有办法从fstream 检索FILE*,但似乎没有办法做到这一点。

    不是一个简单的、完全便携的。请参阅this one 之类的问题。

    如果您真的想要 FILE*,请使用 C API。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多