A biblioteca C não define errnocomo 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:
O <errno.h>arquivo de cabeçalho define a variável inteira errno, que é definida por chamadas do sistema e algumas funções da biblioteca no caso de um erro para indicar o que deu errado. Seu valor é significativo apenas quando o valor de retorno da chamada indica um erro (ou seja, -1da maioria das chamadas do sistema; -1ou NULLda maioria das funções da biblioteca); uma função que sucede é permitida a mudança errno.
A justificativa do ANSI C afirma que o comitê considerou mais prático adotar e padronizar a prática existente de uso errno.
O mecanismo de relatório de erros centrado na configuração de errnoé geralmente considerado com tolerância, na melhor das hipóteses. Requer um `` acoplamento patológico '' entre as funções da biblioteca e faz uso de uma célula de memória gravável estática, que interfere na construção de bibliotecas compartilháveis. No entanto, o Comitê preferiu padronizar esse mecanismo existente, embora deficiente, em vez de inventar algo mais ambicioso.
Quase sempre existe uma maneira de verificar se há erros fora da verificação, se errnotiver sido definido. Verificar se errnoo 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 de fread()ou fwrite().
Curiosamente, seu exemplo de uso strtod()é um dos casos em que errnoé necessário definir 0 antes da chamada para detectar corretamente se ocorreu um erro. Todas as strto*()funções string para number têm esse requisito, porque um valor de retorno válido é retornado mesmo diante de um erro.
errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
/*...parse error */
} else if (errno == ERANGE) {
if (x == 0) {
/*...underflow */
} else if (x == HUGE_VAL) {
/*...positive overflow */
} else if (x == -HUGE_VAL) {
/*...negative overflow */
} else {
/*...unknown range error? */
}
}
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 positivo doublee se está ou não errnodefinido como está definido para ERANGEimplementação 2 .
Na verdade, existe uma extensa redação de recomendação de certificado que recomenda sempre definir errno0 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 definidas errnomesmo que a chamada em si tenha sido bem-sucedida 3 .
O valor de errnoé 0 na inicialização do programa, mas nunca é definido como 0 por nenhuma função da biblioteca. O valor de errnopode ser definido como diferente de zero por uma chamada de função de biblioteca, havendo ou não um erro, desde que o uso de errnonão esteja documentado na descrição da função no Padrão C. É significativo para um programa inspecionar o conteúdo errnosomente após um erro ter sido relatado. Mais precisamente, errnosó é significativo depois que uma função de biblioteca que define errnoerro retorna um código de erro.
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.
errno, pode sempre defini-lo como zero.