我有一个加载的环境,有很多线程打开同一个文件进行读取。 问题是 - 当我fopen时我得到null,但是errno是0。
这怎么可能?
代码:
if ((fParm = fopen(FullFileName.c_str(), "r")) == NULL)
{
printf("%d", GetLastError());
}
正如MSDN中指出的那样 - 在fopen失败后 - 你应该检查errno。这就是我们的工作:
http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx
(忽略printf,原始代码中没有使用它 - 我只是为了简化问题而写它。)
感谢您的帮助。
----------------------编辑------------------------ -
我实际上使用了GetLastError()而不是好的ol' errno - 导致错误显示为0。
答案 0 :(得分:2)
C标准不保证errno
将被设置为有意义的值,尽管POSIX定义它将在失败的情况下返回NULL并设置errno,IEEE Std 1003.1-2013。
因此,根据链接库中使用的实现和已实现的标准集,您可能会看到不同的结果。
您在评论中提到您在Windows上使用GetLastError()
,应该是thread-safe。遗憾的是,您没有编辑主要问题以反映散布在评论中的所有这些事实。
答案 1 :(得分:2)
如果这是Windows并且您使用的是GetLastError
,则您的代码将无效。文档很清楚:
这些函数[
fopen
和_wfopen
]中的每一个都返回指向打开文件的指针。空指针值表示错误。如果filename或mode为NULL或空字符串,则这些函数会触发无效参数处理程序,参数验证中对此进行了描述。如果允许继续执行,则这些函数返回NULL 并将errno 设置为EINVAL。 - MSDN(强调补充)
与其他平台一样,fopen
通过设置errno
返回错误。您不应该调用GetLastError
,而是记录errno
的值。它们是两个完全不同的东西。
在某些情况下,调用GetLastError
可能会发生意外。如果错误的根本原因是来自Windows API中的另一个函数的错误(如CreateFile
),那么可能会调用SetLastError
那个其他函数,并且很可能{{1}中没有其他代码将改变该值,因此有时可能会发生正确的错误。但如果错误来自fopen
本身,fopen
将无法提供正确的信息。
答案 2 :(得分:0)
我们必须猜测,因为您没有向我们展示您的真实代码。但有一种可能性:你的真实代码是这样的:
if ((fParm = fopen(FullFileName.c_str(), "r")) == NULL)
{
SomeLogMacro(Severity, "%d", errno);
}
那个宏扩展到这样的东西:
if ((fParm = fopen(FullFileName.c_str(), "r")) == NULL)
{
do { if (ShouldLog(Severity)) DoLog("%d", errno); } while (false);
}
如果ShouldLog
函数更改了errno
的值,则会记录错误的值。
答案 3 :(得分:0)
阅读MSDN documentation for fopen我发现它没有设置lasterror(它只是在失败时返回0)。阅读MSDN documentation for GetLastError我看到它返回的是,任何人(不是fopen)设置的最后一个错误。
答案 4 :(得分:0)
编辑David Schwartz是对的:问题是fopen没有打电话给GetLastError
- 见下文
好的,我在评论中看到你有#define GetLastError() errno
的其他答案。您应该在初始问题中声明,因为Posix需要errno
是线程安全的,但我不确定它是否在Windows上,当我在MSDN中看到关于全局变量的警告(包括errno
):
对于更安全的功能版本,已弃用这些全局变量,应使用这些版本代替全局变量
但是GetLastError
是线程安全的,只是微软说:
当函数的返回值指示此类调用将返回有用数据时,应立即调用GetLastError函数。这是因为有些函数在成功时调用SetLastError为零,消除了最近失败函数设置的错误代码。
所以唯一万无一失的方法是拥有一个本地变量,比如说lastError
并执行:
if ((fParm = fopen(FullFileName.c_str(), "r")) == NULL)
{
int lastError = errno; // in reality calls GetLastError immediately and saves it current value even if other functions later calls SetLastError(0)
printf("%d", lastError);
}
编辑:
事实上,fopen
并未单独调用SetLastError
。以下是该问题的演示:
#include <stdio.h>
#include <windows.h>
#include <errno.h>
int main() {
FILE *fd = fopen("", "r");
int lastErr = GetLastError();
int err = errno;
printf("errno : %d - GetLastError %d\n", err, lastErr);
return 0;
}
结果是:
errno : 22 - GetLastError 0
实际上应该归咎于#define GetLastError() errno
。但在多线程应用程序中,我真的建议您立即将errno
复制到本地变量中。