Advertencia: ignorando el valor de retorno de ‘scanf’, declarado con el atributo warn_unused_result

10 minutos de lectura

avatar de usuario
VIP

#include <stdio.h>

int main() {
    int t;
    scanf("%d", &t);
    printf("%d", t);
    return 0;
}

Compilé el código C anterior usando ideone.com y apareció la siguiente advertencia:

prog.c: En la función ‘principal’:
prog.c:5: advertencia: ignorando el valor de retorno de ‘scanf’, declarado con el atributo warn_unused_result

¿Alguien puede ayudarme a entender esta advertencia?

avatar de usuario
Evan Terán

Los escritores de su libc han decidido que el valor de retorno de scanf no debe ignorarse en la mayoría de los casos, por lo que le han dado un atributo que le dice al compilador que le dé una advertencia.

Si el valor de retorno realmente no es necesario, entonces está bien. Sin embargo, generalmente es mejor verificarlo para asegurarse de que realmente leyó con éxito lo que cree que hizo.

En su caso, el código podría escribirse así para evitar la advertencia (y algunos errores de entrada):

#include <stdio.h>

int main() {
    int t;
    if (scanf("%d", &t) == 1) {
        printf("%d", t);
    } else {
        printf("Failed to read integer.\n");
    }
    return 0;
}

  • Lo que encontré extraño: parece que el compilador emite una advertencia sobre los resultados no utilizados, pero solo se queja de scanf. Tal vez muchos no lo sepan, pero printf también devuelve un valor, y parece que no se queja de ese resultado descartado allí.

    – flolo

    1 de septiembre de 2011 a las 14:44


  • El compilador solo emitirá esa advertencia para las funciones que tengan ese atributo en particular. Si printf falla, no hay mucho que puedas hacer al respecto. Pero scanf puede fallar con bastante facilidad. Todo lo que necesito hacer es escribir 'A' en lugar de un número entero y su programa está roto.

    – Evan Terán

    1 de septiembre de 2011 a las 14:50

  • Gracias por la respuesta chicos. Este problema vino justo hoy. He estado usando el mismo compilador tantas veces antes, pero de repente apareció esta advertencia.

    – vipin

    01/09/2011 a las 15:00


  • @Evan Teran: Ah Thx, no conozco el compilador y pensé que sería una bandera/interruptor/atributo “global”. Pero cuando es un atributo de función y solo algunos lo tienen, entonces lo entiendo.

    – flolo

    1 de septiembre de 2011 a las 15:03

  • Aquí está la documentación en GCC warn_unused_result atributo de función. Si está usando GCC (que usa Ideone) y busca en su stdio.h archivo de encabezado, verás que scanf y sus familiares están etiquetados con el warn_unused_result atributo, pero printf y sus parientes no lo son.

    – Adam Rosenfield

    1 de septiembre de 2011 a las 15:29

avatar de usuario
alejandro c

La advertencia (con razón) indica que es una mala idea no comprobar el valor de retorno de scanf. La función scanf ha sido declarada explícitamente (a través de un atributo de función gcc) para activar esta advertencia si descarta su valor de retorno.

Si realmente quiere olvidarse de este valor de retorno, mientras mantiene contento al compilador (y su conciencia), puede anular el valor de retorno:

(void)scanf("%d",&t);

  • GCC seguirá advirtiendo incluso cuando hagas esto. Ver esta discusión para más información gcc.gnu.org/bugzilla/show_bug.cgi?id=25509

    – Kraffenetti

    6 de diciembre de 2013 a las 15:52

  • Si asigna una variable ficticia, es posible que reciba otra advertencia sobre la variable asignada pero nunca utilizada.

    –Craig McQueen

    19 de junio de 2015 a las 6:09


  • ADVERTENCIA: muchos compiladores optimizarán este lanzamiento vacío, ya que es innecesario, y luego se producirá un error de variable no utilizada.

    – Búho rico

    15/07/2015 a las 20:25

  • @AffluentOwl El void cast es la convención estándar para decir “este resultado no se usa intencionalmente” y es reconocido universalmente, excepto por gcc porque alguien (¿Stallmann?) decidió hace 20 años que no debería haber forma de ignorar un warn_unused_result.

    – fuz

    15 de enero de 2016 a las 15:12

  • (void)! ... se puede utilizar para al menos evitar la gcc advertencia (@kraffenetti @AffluentOwl), consulte gcc.gnu.org/bugzilla/show_bug.cgi?id=66425#c34 .

    – rivo

    28 de enero de 2019 a las 19:54


avatar de usuario
Quigui

Probé tu ejemplo con gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3. La advertencia se emite si y solo si se optimiza, por ejemplo, con la opción -O2 o -O3. Solicitar todas las advertencias (-Wall) no importa. El idioma clásico de lanzar al vacío no tiene efectono suprime la advertencia.

Puedo silenciar la advertencia escribiendo

if(scanf("%d",&t)){};

esto funciona, pero es un poco oscuro para mi gusto. Vacío {} evita otra advertencia -Wempty-body

  • esto puede causar una advertencia adicional de cuerpo vacío del compilador

    – Kraffenetti

    06/12/2013 a las 15:50


  • Si veo ese tipo de código, con un punto y coma al final de un if, pensaré que puede ser un error. Requiere un comentario explicativo como mínimo.

    –Craig McQueen

    19 de junio de 2015 a las 6:11


  • ¿Tantos votos a favor para un consejo de vaquero tan irresponsable? estremecimiento

    – Mawg dice que reincorpore a Monica

    13 de julio de 2016 a las 17:23


  • Mawg tiene razón, siempre debe verificar el valor de retorno de scanf. Estaba buscando una manera de silenciarlo, más como un deporte, no como un consejo para una buena codificación. Todavía me parece extraño que (a) la optimización afecte si recibe la advertencia, y (b) -Wall no.

    – Quigui

    4 de abril de 2017 a las 14:58

Hacer esto:

int main() {
    int t;
    int unused __attribute__((unused));
    unused = scanf("%d",&t);
    printf("%d",t);
    return 0;
}

avatar de usuario
DrBeco

Después de leer todas las respuestas y comentarios en esta página, no veo estas otras opciones para evitar la advertencia:

Cuándo compilando con gcc puede agregar a su línea de comando:

gcc -Wall -Wextra -Wno-unused-result proc.c -o prog.x

Otra opción es usar -O0 como “nivel de optimización cero” ignora la advertencia.

usando cast para (void) es simple inútil al compilar con gcc

Si está depurando su código, siempre puede usar assert() como en el siguiente ejemplo:

u = scanf("%d", &t);
assert(u == 1);

Pero ahora, si desactiva la afirmación a través de #define NDEBUG obtendrás un -Wunused-but-set-variable. A continuación, puede desactivar este segunda advertencia por una de dos maneras:

  1. agregando -Wno-unused-but-set-variable para usted gcc línea de comando, o
  2. Declarando la variable con atributo: int u __attribute__((unused));

Como se señaló en otra respuesta, la segunda opción lamentablemente no es muy portátil, aunque parece la mejor opción.

Por fin, lo definido MACRO abajo puede ayudarte si eres Por supuesto desea ignorar el retorno de una función determinada, pero no se siente cómodo desactivando las advertencias para todos retornos no utilizados de funciones:

#define igr(x) {__typeof__(x) __attribute__((unused)) d=(x);} 

double __attribute__ ((warn_unused_result)) fa(void) {return 2.2;}
igr(fa());

Ver también esta respuesta

  • los assert es un abuso. Si una assert falla, el programador escribió un código con errores. si entro A en su programa, su código aborta, por lo tanto, tiene una falla.

    – Antti Haapala — Слава Україні

    7 sep 2018 a las 16:56

  • Gracias por tu comentario. Acepto que si usas assert como usted está malinterpretando mi respuesta es de hecho un abuse. La respuesta anterior enumera varias opciones para lidiar con el “retorno no utilizado de scanf”, ese es el punto principal. los assert estados parciales si la depuración. Creo que es bueno “escribir” todas las opciones como una respuesta informativa educativa para que las personas puedan aprender todas las herramientas y tomar decisiones informadas. También es por eso que creo que su comentario es útil, para que la gente no lo lea mal y abuse de la assert() hacer un trabajo que no es para ello. Gracias.

    – DrBeco

    7 sep 2018 a las 17:36

Una forma de solucionar esto es la IGUR() función como se ve a continuación. Extremadamente feo, pero sin embargo algo portátil. (Para compiladores antiguos que no entienden inline sólo #define inline /*nothing*/como siempre.)

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

inline void IGUR() {}  /* Ignore GCC Unused Result */
void IGUR();  /* see https://stackoverflow.com/a/16245669/490291 */

int
main(int argc, char **argv)
{
  char  buf[10*BUFSIZ];
  int   got, fl, have;

  fl    = fcntl(0, F_GETFL);
  fcntl(0, F_SETFL, fl|O_NONBLOCK);
  have = 0;
  while ((got=read(0, buf, sizeof buf))>0)
    {
      IGUR(write(1, buf, got));
      have = 1;
    }
  fcntl(0, F_SETFL, fl);
  return have;
}

Por cierto, este ejemplo, sin bloqueo, copia de stdin para stdout hasta que se leyeron todas las entradas en espera, volviendo true (0) si no había nada, si no false (1). (Evita el retraso de 1s en algo como while read -t1 away; do :; done en bash.)

Compila sin previo aviso bajo -Wall (Debian Jessie).

Editar: IGUR() debe definirse sin inline, también, de modo que esté disponible para el enlazador. más con cc -O0 podría fallar. Ver: https://stackoverflow.com/a/16245669/490291

Edit2: más nuevo gcc exigir inline estar antes void.

  • los assert es un abuso. Si una assert falla, el programador escribió un código con errores. si entro A en su programa, su código aborta, por lo tanto, tiene una falla.

    – Antti Haapala — Слава Україні

    7 sep 2018 a las 16:56

  • Gracias por tu comentario. Acepto que si usas assert como usted está malinterpretando mi respuesta es de hecho un abuse. La respuesta anterior enumera varias opciones para lidiar con el “retorno no utilizado de scanf”, ese es el punto principal. los assert estados parciales si la depuración. Creo que es bueno “escribir” todas las opciones como una respuesta informativa educativa para que las personas puedan aprender todas las herramientas y tomar decisiones informadas. También es por eso que creo que su comentario es útil, para que la gente no lo lea mal y abuse de la assert() hacer un trabajo que no es para ello. Gracias.

    – DrBeco

    7 sep 2018 a las 17:36

En realidad, depende de lo que necesite, si solo desea deshabilitar la advertencia del compilador, puede ignorar el valor de retorno de la función mediante la conversión forzada o simplemente puede manejarlo, el significado de la scanf La función es el recuento de la entrada del usuario.

==== actualizar ====

Puedes usar

(void) scanf("%d",&t);

para ignorar el valor de retorno de scanf

  • Menos uno por abogar por ignorar las advertencias. Personas más inteligentes que tú y yo somos responsables de ellos. Te dicen cosas útiles. Prestarles atención conduce a una mejor calidad del código. Ignóralos bajo tu propio riesgo y, por favor, no abogues por que otros los ignoren o los supriman.

    – Mawg dice que reincorpore a Monica

    9 de agosto de 2016 a las 16:18

  • lo que sea, sé dónde está la advertencia y sé que dañará mi programa. Y algún proyecto puede tratar la advertencia como un error. Me refiero a deshacerse de la advertencia

    – Actón

    11 de agosto de 2016 a las 8:28

  • Deshazte de las advertencias manejando el error, no eludiéndolos…

    – Woodrow Douglass

    17/10/2016 a las 18:03

  • Esto no funciona (ya) para gcc 5.4.x. Sigo recibiendo la misma advertencia cuando pongo un molde (vacío) delante de la función.

    – Carlos Wood

    15 de diciembre de 2016 a las 16:44

  • @WoodrowDouglas Las advertencias no son errores. Cuando ve una advertencia, examina la línea y determina si está bien como está. En algunos casos, realmente desea ignorar el retorno de scanf, por lo que no tener una forma de eliminar la advertencia para esa línea es, para decirlo sin rodeos, tonto. No desea que el código ya examinado y determinado como seguro emita advertencias porque entonces está aumentando la relación ruido/señal en la salida del compilador.

    – Lelanthran

    7 abr 2018 a las 18:49


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad