O padrão C exige que nenhuma função da biblioteca padrão C seja definida errno
como zero. Por que exatamente é isso?
Eu pude entender que é útil chamar várias funções e verificar apenas errno
após a última - por exemplo:
errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
// either "strtod" or "strtol" failed
else
// both succeeded
No entanto, isso não é considerado "má prática"? Desde que você só está verificando errno
no final, você só sabe que uma das funções fez falhar, mas não que função falhou. É simplesmente saber que algo falhou o suficiente para a maioria dos programas práticos?
Tentei procurar vários documentos C Rationale, mas muitos deles não têm muitos detalhes <errno.h>
.
errno
, pode sempre defini-lo como zero.errno
um valor diferente de zero, mesmo que seja bem-sucedida. (Pode chamar alguma outra função que não, mas isso não constitui uma falha na função externa.)Respostas:
A biblioteca C não define
errno
como 0 por razões históricas 1 . O POSIX não afirma mais que suas bibliotecas não alterarão o valor em caso de sucesso, e a nova página de manual do Linuxerrno.h
reflete isso:A justificativa do ANSI C afirma que o comitê considerou mais prático adotar e padronizar a prática existente de uso
errno
.Quase sempre existe uma maneira de verificar se há erros fora da verificação, se
errno
tiver sido definido. Verificar seerrno
o conjunto foi configurado nem sempre é confiável, pois algumas chamadas exigem a chamada de uma API separada para obter o motivo do erro. Por exemplo,ferror()
é usado para verificar se há um pequeno resultado defread()
oufwrite()
.Curiosamente, seu exemplo de uso
strtod()
é um dos casos em queerrno
é necessário definir 0 antes da chamada para detectar corretamente se ocorreu um erro. Todas asstrto*()
funções string para number têm esse requisito, porque um valor de retorno válido é retornado mesmo diante de um erro.O código acima é baseado no comportamento de
strtod()
conforme documentado no Linux . O padrão C apenas estipula que o subfluxo não pode retornar um valor maior que o menor positivodouble
e se está ou nãoerrno
definido como está definido paraERANGE
implementação 2 .Na verdade, existe uma extensa redação de recomendação de certificado que recomenda sempre definir
errno
0 antes de uma chamada de biblioteca e verificar seu valor após a chamada indicar que ocorreu uma falha . Isso ocorre porque algumas chamadas de biblioteca serão definidaserrno
mesmo que a chamada em si tenha sido bem-sucedida 3 .1. Anteriormente, afirmei que era para evitar mascarar um erro de uma chamada anterior. Não consigo encontrar nenhuma evidência para apoiar esta afirmação. Eu também tive um
printf()
exemplo falso .2. Obrigado ao @chux por apontar isso. A referência é C.11 §7.22.1.3 ¶10.
3. Apontado por @KeithThompson em um comentário.
fonte
errno
aERANGE
implementação é definida no caso de subfluxo, na verdade não existe uma maneira portátil de detectar subfluxo. Meu código seguiu o que encontrei na página de manual do Linux no meu sistema.strto*
funções são exatamente o motivo pelo qual perguntei se meu exemplo seria considerado uma má prática, mas é a única maneira pela qualerrno
não ser definido como zero seria útil ou até aplicável.errno
pode ser definido mesmo no caso de sucesso, portanto, apenas usar o fato de que foi definido não é realmente um indicador suficientemente bom de que ocorreu um erro. Você deve verificar os resultados das chamadas individuais para saber se ocorreu algum erro.Você pode fazer a verificação de erros para as duas chamadas de função, se realmente se importa.
Como nunca sabemos como a função mach é chamada em um processo, como a lib pode definir erros para cada função, certo?
fonte
Mudar arbitrariamente o errorno é análogo a 'pegar e engolir' uma exceção. Antes que houvesse exceções que se propagariam por diferentes camadas de um programa e finalmente chegassem a um ponto em que o chamador capturasse e respondesse à exceção de alguma maneira ou simplesmente passasse a bola, havia erros. Não alterar o erro, a menos que você esteja manipulando, substituindo, tratando o erro como irrelevante, é essencial para esse paradigma de propagação da manipulação de erros de primeira geração.
fonte