2010-10-06 13 views
7

Es seguro llamar al errno varias veces cuando se trata del mismo error. ¿O es más seguro trabajar con una copia local?¿Se deben evitar las llamadas consecutivas a `errno`?

Esta muestra ilustra mi pregunta:

// If recvfrom() fails it returns -1 and sets errno to indicate the error. 
int res = recvfrom(...); 
if (res < 0) 
{ 
    // Risky? 
    printf("Error code: %d. Error message: %s\n", errno, strerror(errno)); 

    // Safer alternative? 
    int errorNumber = errno; 
    printf("Error code: %d. Error message: %s\n", errorNumber, strerror(errorNumber)); 
} 
+1

+1 pregunta interesante que resulta tener una respuesta no trivial y posibles consecuencias prácticas. –

Respuesta

5

El valor de errno se definirá sólo después de una llamada a una función para la que se indica explícitamente a ser ajustado y hasta que se cambie por el siguiente llamada de función o si la aplicación le asigna un valor.

http://www.opengroup.org/onlinepubs/009695399/functions/errno.html

Sin embargo, incluso strerror en teoría podría contar como una llamada de función que puede cambiarlo (ver comentario de schot) por lo que debería, en teoría, todavía ir con su save-primera forma.

+1

Sin embargo, printf puede causar un cambio a errno. La página man en http://linux.die.net/man/3/errno (creo que es de Linux) advierte contra el uso en printf. Sin embargo, esto no es un problema para su situación específica: el compilador evaluará 'errno' y' strerror (errno) 'antes de llamar a printf. – Habbie

+1

Pero la llamada a 'strerror' podría cambiar' errno'. Aunque no creo que haya ninguna implementación lo suficientemente estúpida/malvada para hacer esto. (Excepto quizás una DeathStation 9000). – schot

+0

Es cierto, y el compilador puede decidir evaluar strerror (errno) antes de evaluar errno. Estoy actualizando mi respuesta. – Habbie

1

errno es variable y no funciona. Cuando lo usas, no se puede restablecer. Por lo tanto, está bien utilizar errno número de veces, asumiendo que no se llama a ninguna función que pueda cambiar/restablecer el errno.

+1

'errno' no es una variable. –

2

Cualquier función de biblioteca estándar, incluyendo printf y strerror está permitido cambiar errno, incluso si se produce realmente ningún error:

7,5 3 El valor de errno es cero al inicio del programa, pero nunca se establece en cero por cualquier función de biblioteca. 170) El valor de errno se puede establecer en distinto de cero por una llamada de función de biblioteca si hay o no un error, proporciona el uso de errno se no documentado en la descripción de la función de en este Norma Internacional.

+1

Tangencialmente relacionado: ¿se puede encontrar cualquier lenguaje en el estándar que prohíba a 'strtol' y a la familia configurar 'errno' a' ERANGE' cuando no se produce un desbordamiento? El procedimiento estándar es establecer 'errno' en 0 antes de llamar a estas funciones, y verificar' errno' si se devuelve 'LONG_MIN' o' LONG_MAX', pero si pudieran establecer 'errno' en' ERANGE' sin ningún motivo, este la prueba estándar parece inválida ... –

+0

@R ..: Si el uso de errno se define para una función específica, entonces no hay otro comportamiento que explícitamente establecido por 7.5: "siempre que el uso de errno no esté documentado en la descripción de la función ". – Secure

+0

Guau, estaba justo allí en tu cita y me lo perdí ... –

1

general hoy en día errno es algo mucho más complicado que una variable:

... errno que se expande a un valor-modificable que tiene el tipo int, cuyo valor se establece en un número de error positivo por varias funciones de la biblioteca . No se especifica si errno es una macro o un identificador declarado con un enlace externo . Si una definición de macro es suprimida para acceder a un objeto real , o un programa define un identificador con el nombre errno, el comportamiento no está definido.

E.g. en POSIX, se garantiza que evaluará algo específico para el hilo actual. Por lo tanto, puede tener un costo de acceso que es mayor que para una variable simple.

Así que sí, me gustaría obtener una copia local si el rendimiento es una preocupación, aunque nunca lo hice de esta manera.

0

Yo solo estaba investigando esto yo mismo y creo que otra función podría ser más adecuada para este problema, perror.perror es bastante simple, por ejemplo, si malloc algo de memoria y desea que el tipo de mensaje de error significativa la strerror proporciona si malloc falla:

char **str_array = (char**) malloc(SOME_CONSTANT * sizeof(char*)); 
if (str_array == NULL){ 
    perror("malloc failed on str_array"); 
} 

perror imprime la cadena que ha escrito, añade un espacio, a continuación, un punto y coma, y luego imprime el texto de error legible por humanos. Tampoco parece tener el efecto secundario que tiene strerror, a menos que interprete incorrectamente la página de manual porque no tiene una sección para ERRORES: http://man7.org/linux/man-pages/man3/perror.3.html.

También estoy realizando llamadas sucesivas que pueden fallar, y perror parece tener menos líneas de código y una mejor sintaxis. Sin embargo, soy más nuevo en C, por lo tanto, edite o elimine si esta información es inexacta.

Cuestiones relacionadas