2014-10-02 4 views
-2

У меня есть загруженная среда с большим количеством потоков, открывающих один и тот же файл для чтения. проблема - я получаю null, когда я fopen, но errno равен 0.fopen не работает с GetLastError() = 0 - почему?

Как это возможно?

Код:

if ((fParm = fopen(FullFileName.c_str(), "r")) == NULL) 
    { 
     printf("%d", GetLastError()); 
    } 

Как указано в MSDN - после того, как Еореп терпит неудачу - вы должны проверить ERRNO. и это то, что мы делаем:

http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx

(игнорировать Printf, он не используется в исходном коде - я написал только упрощать вопрос).

Благодарим за помощь.

---------------------- РЕДАКТИРОВАТЬ ----------------------- ---

я фактически использовал GetLastError() вместо старого доброго»ERRNO - который вызвал ошибку, чтобы показать 0.

+0

fopen - это очень старый унаследованный код. Я не использую printf, мы записываем его в файл журнала - и я использовал его здесь только для упрощения вопроса – ArielB

+0

Но бит 'c_str' - это не так! Конечно, если это наследие, оно используется для работы –

+0

@EdHeal - полное имя файла - это пользовательский класс, который мы используем, он указывает на правильный символ *, но это не моя проблема. Я хочу сосредоточиться на том, почему это происходит. – ArielB

ответ

2

Если это Windows и вы используете GetLastError, ваш код не будет работать. Документация ясна:

Каждая из этих функций [fopen и _wfopen] возвращает указатель на открытый файл. Значение нулевого указателя указывает на ошибку. Если имя файла или режим NULL или пустая строка, эти функции запускают недействительный обработчик параметров, который описан в разделе «Проверка параметров». Если выполнение разрешено продолжить, эти функции возвращают NULL и устанавливают errno в EINVAL. - (подчеркивание добавлено) MSDN

Как и на других платформах, fopen возвращает ошибку, установив errno. Вы не должны звонить GetLastError, но регистрируете значение errno.Это две совершенно разные вещи.

Вызов GetLastError может быть случайным в некоторых случаях. Если основной причиной ошибки является ошибка другой функции в Windows API (например, CreateFile), возможно, что другая функция может вызвать SetLastError, и вполне возможно, что никакой другой код в fopen не изменит это значение, поэтому иногда это может произойти для правильной ошибки. Но если ошибка исходит от fopen, то GetLastError не даст правильной информации.

+0

uhm, так как я могу получить последнюю ошибку? что я так печатаю? – ArielB

+0

EINVAL - 22, но я получаю 0 ... – ArielB

+0

@ArielB Вы на 100% уверены, что проверяете 'errno', не называете' GetLastError'? –

2

стандарт C не гарантирует, что errno будет установлен содержательного значения, хот POSIX Определяет что он вернет NULL в случае отказа и установит errno, IEEE Std 1003.1-2013.

Так что в зависимости от реализации, используемой в связанных библиотеках, и набора стандартов, которые были реализованы, вы можете увидеть разные результаты.

Вы упомянули в комментариях, что вы использовали GetLastError() на Windows, который должен быть thread-safe. К сожалению, вы не отредактировали главный вопрос, чтобы отразить все эти факты, которые разбросаны в комментариях.

+1

реализация, в частности библиотека, а не компилятор. – Deduplicator

+0

POSIX относится к операционной системе Unix? мы используем окна .. и я не думаю, что это соответствует – ArielB

+0

Возможно, вы можете указать более подробную информацию о своей среде, чтобы мы могли проверить? – BlueTrin

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, вы будете регистрировать неверное значение ,

+0

Я понимаю, что вы сказали это не проблема – ArielB

0

Чтение MSDN documentation for fopen Я вижу, что он не устанавливает lasterror (он просто возвращает 0 при ошибке). Чтение MSDN documentation for GetLastError Я вижу, что он возвращает только, ну, последнюю ошибку, когда-либо установленную кем-либо (не fopen).

+0

Точнее, 'GetLastError' возвращает результаты последнего вызова' SetLastError'. 'fopen', безусловно, вызывает нечто вроде' CreateFile', которое бы вызывало 'SetLastError', если оно не получилось, но то, что происходит в' fopen', после этого - это чья-то догадка. Я предполагаю, что он отображает результаты 'GetLastError' в' errno' и очищает 'GetLastError'. (По крайней мере, так я бы его реализовал.) –

+0

Забудьте об «GetLastError», мы создали собственный GetLastERror - мы просто распечатываем errno. – ArielB

0

Редактировать Дэвид Шварц был прав: проблема заключается в том, что Еореп не вызывает GetLastError - смотрите ниже

Хорошо, я увидел в комментариях к другим ответам, которые вы имеете в #define GetLastError() errno. Вы должны были указать, что в начальном вопросе, поскольку errno должен быть потокобезопасным Posix, но я не уверен, что он находится в Windows, когда я вижу это предупреждение в MSDN о глобальных переменных (включая errno):

Эти глобальные переменные являются нежелательными для более безопасных функциональных версий, которые должны быть использованы вместо глобальной переменной

Но GetLastErrorявляется поточно, просто Microsoft говорит:

Вы должны сразу вызвать функцию 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); 
    } 

EDIT:

В самом деле, 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 в локальную переменную.

+0

вы можете объяснить? Какая разница, чтобы поместить errno в локальную переменную? я отправляю его в функцию журнала, поэтому его нужно скопировать в любом случае «по значению» – ArielB

+0

@ArielB Oups, я понял: Дэвид Шварц прав: проблема в том, что fopen не называет 'GetLastError'. Я редактировал свой пост ... –

Смежные вопросы