关于 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.
Opens a file. These functions are deprecated because more-secure
versions are available; see _sopen_s, _wsopen_s.
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,还有前面提到的_open。 MSDN 中的一些引述:
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,比如调用GetFileInformationByHandle
或CreateFileMapping
,你需要一个HANDLE
你应该调用 CreateFile
来打开文件。
如果您的程序已经为 POSIX 系统编写,那么您可以使用 open
来更轻松地将您的程序移植到 Windows .如果您只是为 Windows 编写代码,那么使用此接口没有任何优势。
如果你的程序只需要做打开、读取、写入等基本的文件操作,那么fopen
就足够了,它也可以在其他系统上运行。 FILE *
可以(通常是)由您的应用程序缓冲,并支持方便的操作,如 fprintf
、fscanf
和 fgets
。如果您想在 CreateFile
或 open
返回的文件上调用 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,情况就会有所不同。
我看到这3个函数都与打开文件有关。
open:
This POSIX function is deprecated. Use the ISO C++ conformant _open instead.
Opens a file. These functions are deprecated because more-secure versions are available; see _sopen_s, _wsopen_s.
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,还有前面提到的_open。 MSDN 中的一些引述:
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
andopen
函数是 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,比如调用
GetFileInformationByHandle
或CreateFileMapping
,你需要一个HANDLE
你应该调用CreateFile
来打开文件。如果您的程序已经为 POSIX 系统编写,那么您可以使用
open
来更轻松地将您的程序移植到 Windows .如果您只是为 Windows 编写代码,那么使用此接口没有任何优势。如果你的程序只需要做打开、读取、写入等基本的文件操作,那么
fopen
就足够了,它也可以在其他系统上运行。FILE *
可以(通常是)由您的应用程序缓冲,并支持方便的操作,如fprintf
、fscanf
和fgets
。如果您想在CreateFile
或open
返回的文件上调用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,情况就会有所不同。