关于 MSVC 编译器,open()、open() 和 fopen() 之间的区别?

Differenence among open(), _open(), and fopen() with regard to MSVC compiler?

我看到这3个函数都与打开文件有关。

open:

This POSIX function is deprecated. Use the ISO C++ conformant _open instead.

_open:

Opens a file. These functions are deprecated because more-secure versions are available; see _sopen_s, _wsopen_s.

fopen:

Opens a file. More-secure versions of these functions that perform additional parameter validation and return error codes are available; see fopen_s, _wfopen_s.

那么,为什么是三个?什么时候使用哪个?我认为 POSIX 很好,但为什么 MSDN 说 open 的 POSIX 版本已弃用?是否有任何与前导下划线相关的命名约定,以便我可以根据第一眼选择正确的函数?

当我查看 ACPICA code 时,我看到以下代码: _XXX版本似乎可以禁用一些MS语言扩展,这些扩展到底是什么?

/*
 * Map low I/O functions for MS. This allows us to disable MS language
 * extensions for maximum portability.
 */
#define open            _open
#define read            _read
#define write           _write
#define close           _close
#define stat            _stat
#define fstat           _fstat
#define mkdir           _mkdir
#define snprintf        _snprintf
#if _MSC_VER <= 1200 /* Versions below VC++ 6 */
#define vsnprintf       _vsnprintf
#endif
#define O_RDONLY        _O_RDONLY
#define O_BINARY        _O_BINARY
#define O_CREAT         _O_CREAT
#define O_WRONLY        _O_WRONLY
#define O_TRUNC         _O_TRUNC
#define S_IREAD         _S_IREAD
#define S_IWRITE        _S_IWRITE
#define S_IFDIR         _S_IFDIR

加 1

似乎单下划线前缀 _XXX 是 Microsoft 的惯例。比如_DEBUG_CrtSetDbgFlag,还有前面提到的_openMSDN 中的一些引述:

In Microsoft C++, identifiers with two leading underscores are reserved for compiler implementations. Therefore, the Microsoft convention is to precede Microsoft-specific keywords with double underscores. These words cannot be used as identifier names.

Microsoft extensions are enabled by default. To ensure that your programs are fully portable, you can disable Microsoft extensions by specifying the ANSI-compatible /Za command-line option (compile for ANSI compatibility) during compilation. When you do this, Microsoft-specific keywords are disabled.

When Microsoft extensions are enabled, you can use the Microsoft-specific keywords in your programs. For ANSI compliance, these keywords are prefaced by a double underscore. For backward compatibility, single-underscore versions of all the double-underscored keywords except __except, __finally, __leave, and __try are supported. In addition, __cdecl is available with no leading underscore.

The __asm keyword replaces C++ asm syntax. asm is reserved for compatibility with other C++ implementations, but not implemented. Use __asm.

The __based keyword has limited uses for 32-bit and 64-bit target compilations.

虽然根据上面的引述,__int64_int64 应该都有效,但是 Visual Studio 没有为 _int64 提供语法高亮显示。但是_int64也可以编译。

添加 2

snprintf() and _snprintf()

  • 就Windows而言,打开文件的功能是CreateFile。这个 returns 一个 HANDLE 由 Kernel32.dll 提供,而不是由 Visual Studio 提供。 HANDLE 可以传递给其他 Windows API 函数。

  • _open and open 函数是 POSIX 兼容性函数,可帮助您编译为 POSIX(Linux、macOS、BSD、Solaris、等)在 Windows 上。这些函数由 Visual Studio 的 C 运行时定义,并且可能在内部调用 CreateFile。函数的 POSIX 名称是 open,但如果您已经在代码中定义了一个名为 open 的函数,则此处的函数定义为 _open。函数 returns 一个 int 可以传递给其他 POSIX 函数。在Windows上,此接口是Visual Studio提供的兼容性API,但在Linux和macOS上,此接口是操作系统的直接接口,就像HANDLE 在 Windows.

  • fopen 函数是 C 标准的一部分。它由 Visual Studio 的 C 运行时定义,并且大概在内部调用 CreateFile。它returns一个FILE *可以传递给C标准定义的其他函数。

因此,总结选项:

  • 如果你需要直接使用Windows API,比如调用GetFileInformationByHandleCreateFileMapping,你需要一个HANDLE你应该调用 CreateFile 来打开文件。

  • 如果您的程序已经为 POSIX 系统编写,那么您可以使用 open 来更轻松地将您的程序移植到 Windows .如果您只是为 Windows 编写代码,那么使用此接口没有任何优势。

  • 如果你的程序只需要做打开、读取、写入等基本的文件操作,那么fopen就足够了,它也可以在其他系统上运行。 FILE * 可以(通常是)由您的应用程序缓冲,并支持方便的操作,如 fprintffscanffgets。如果您想在 CreateFileopen 返回的文件上调用 fgets,您必须自己编写。

可以将文件句柄从一个 API 转换为另一个,但您必须注意所有权问题。 "Ownership" 并不是一个真正的技术概念,它只是描述了谁负责管理一个对象的状态,你希望避免销毁不属于你的对象,避免同一个对象有多个所有者。

  • 对于 Windows API,您可以使用 _open_osfhandle()HANDLE 创建一个 FILE *,并且 _get_osfhandle()FILE * 得到 HANDLE。但是,在这两种情况下,句柄都属于 FILE *.

  • 对于 POSIX API,您可以使用 fdopen()int 文件描述符创建 FILE *,并且您可以使用 fileno()FILE * 获取 int 文件描述符。同样,在这两种情况下,文件都属于 FILE *.

请注意,Windows 文件名是 wchar_t 的数组,但 macOS / Linux / 等文件名是 char 的数组,因此可移植性很复杂。

如果您使用不同的 C 运行时,例如 MinGW,或者如果您使用 Windows 子系统 Linux,情况就会有所不同。