De acuerdo con los documentos de Microsoft, la API char * strerror(int errnum)
"asigna errnum a una cadena de mensaje de error y devuelve un puntero a la cadena"
En la práctica resultó que hay un aspecto importante que no está cubierto por la descripción:
Este es el código que representa este comportamiento:
printf("---------- print separately [OK] ----------\n"); printf("strerror(1)=(%s), ptr=(%p)\n", strerror(1), strerror(1)); printf("strerror(2)=(%s), ptr=(%p)\n", strerror(2), strerror(2)); printf("---------- print together [BUG] ----------\n"); printf("strerror(1)=(%s), strerror(2)=(%s)\n", strerror(1), strerror(2)); printf("ptr_1=(%p), ptr_2=(%p)\n", strerror(1), strerror(2)); printf("---------- print together, get pointers separately [BUG] ----------\n"); const char * s1 = strerror(1); const char * s2 = strerror(2); printf("strerror(1)=(%s), strerror(2)=(%s)\n", s1, s2); printf("ptr_1=(%p), ptr_2=(%p)\n", s1, s2); printf("---------- --------------------------- ----------\n");Producción:
---------- print separately [OK] ---------- strerror(1)=(Operation not permitted), ptr=(000002756DE6BD90) strerror(2)=(No such file or directory), ptr=(000002756DE6BD90) ---------- print together [BUG] ---------- strerror(1)=(Operation not permitted), strerror(2)=(Operation not permitted) ptr_1=(000002756DE6BD90), ptr_2=(000002756DE6BD90) ---------- print together, get pointers separately [BUG] ---------- strerror(1)=(No such file or directory), strerror(2)=(No such file or directory) ptr_1=(000002756DE6BD90), ptr_2=(000002756DE6BD90) ---------- --------------------------- ----------No se usaron banderas de optimización del compilador. El mismo código funciona correctamente en Linux con gcc.
ACTUALIZACIÓN: Las preguntas están respondidas.
P: ¿Este comportamiento es un ERROR?
P: ¿Existe otra API mejor que funcione como strerror en Linux?
La memoria devuelta por strerror se puede modificar mediante llamadas posteriores a la función.
En su lugar, use strerror_s que le permite proporcionar un búfer para escribir la cadena de error.
char s1[200], s2[200]; strerror_s(s1, sizeof s1, 1); strerror_s(s2, sizeof s2, 2);Esto no es un error. Según la documentación de POSIX para strerror:
El puntero de cadena devuelto podría invalidarse o el contenido de la cadena podría sobrescribirse con una llamada posterior a
strerror()
Entonces, si lo llama dos veces en una sola declaración, no debe esperar que más de uno de los valores sea válido (y sería perfectamente aceptable que su código se bloquee o haga otras cosas extrañas).
La razón subyacente probablemente se deba a que la biblioteca de Microsoft C utiliza un solo búfer fijo para el valor de retorno de strerror , por lo que cada llamada sobrescribe el valor retenido anterior. Esto está específicamente permitido por el estándar, para facilitar la implementación.