Ler as páginas do manual e algum código não me ajudou muito a entender a diferença entre - ou melhor, quando devo usar - perror("...")
ou fprintf(stderr, "...")
.
Ler as páginas do manual e algum código não me ajudou muito a entender a diferença entre - ou melhor, quando devo usar - perror("...")
ou fprintf(stderr, "...")
.
Respostas:
Chamar perror
fornecerá o valor interpretado de errno
, que é um valor de erro local de thread gravado por syscalls POSIX (ou seja, cada thread tem seu próprio valor para errno
). Por exemplo, se você fez uma chamada para open()
, e um erro foi gerado (ou seja, ele retornou -1
), você poderia ligar perror
imediatamente depois para ver qual era o erro real. Lembre-se de que, se você chamar outras syscalls nesse ínterim, o valor em errno
será sobrescrito e a chamada perror
não terá nenhuma utilidade para diagnosticar seu problema se um erro tiver sido gerado por uma syscall anterior.
fprintf(stderr, ...)
por outro lado, pode ser usado para imprimir suas próprias mensagens de erro personalizadas. Ao imprimir para stderr
, você evita que a saída do relatório de erros seja misturada com a saída "normal" que deveria estar stdout
.
Lembre-se de que fprintf(stderr, "%s\n", strerror(errno))
é semelhante a perror(NULL)
porque uma chamada para strerror(errno)
gerará o valor da string impressa para errno
e você pode então combiná-lo com qualquer outra mensagem de erro personalizada via fprintf
.
strerror
não precisa ser thread-safe. É estúpido, mas esse é o padrão. strerror_l
pode ser usado como substituto imediato nos sistemas POSIX 2008. strerror_r
também está disponível em sistemas mais antigos, mas tem problemas realmente desagradáveis com alguns sistemas que possuem versões não conformes.
perror
acrescenta '\n'
no final então o formato ficaria "%s\n"
, não?
strerror_s
na verdade não é tão ruim como interface.
_s
lixo no padrão foi basicamente um jogo da MS ("Se você adotar nossas interfaces, consideraremos realmente fazer nossos produtos suportarem seu padrão.") E é claro que agora eles não estão seguindo adiante. Na verdade, concordo que essa interface não é ruim em si mesma. O que é ruim é a propaganda (na forma de avisos do compilador) de que a maior parte da biblioteca padrão é "insegura" e que toda a família de _s
funções deve ser usada em vez das padrão.
Eles fazem coisas bem diferentes.
Você usa perror()
para imprimir uma mensagem stderr
que corresponda a errno
. Você usa fprintf()
para imprimir qualquer coisa para stderr
, ou qualquer outro fluxo. perror()
é uma função de impressão muito especializada:
perror(str);
é equivalente a
if (str)
fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
fprintf(stderr, "%s\n", strerror(errno));
perror(const char *s)
: imprime a string fornecida seguida por uma string que descreve o valor atual de errno
.
stderr
: é um fluxo de saída usado para enviar suas próprias mensagens de erro (o padrão é o terminal).
Relevante:
char *strerror(int errnum)
: dê a ele um número de erro e ele retornará a string de erro associada.
perror () sempre escreve em stderr; strerr (), usado junto com fprintf (), pode escrever em qualquer saída - incluindo stderr, mas não exclusivamente.
fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")
Além disso, perror impõe sua própria formatação de texto "texto: descrição do erro"
A função Perror leva mais tempo para realizar a chamada de execução vai do espaço do usuário para o espaço do kernal, enquanto que as chamadas do fprintf vão para a api para o kernal
If you use a function that effects errno then it makes sense to use perror
.Se você usar uma função que não afeta errno e simplesmente retorna um código de erro, você deve usar fprintf (stderr, fmt, ...). Por exemplo, strtol retornará LONG_MAX ou LONG_MIN se uma string estiver fora do intervalo e definir errno como ERANGE. Portanto, se strtol falhar devido a estar fora do intervalo, eu usaria perror.