2012-03-30 41 views
10

Si una función tiene un tipo de devolución que no sea void, y la función no devuelve nada, entonces supongo que el compilador devuelve un valor basura (posiblemente visto como un valor no inicializado). Sucede en el momento de la compilación, entonces ¿por qué no lanzar un error?Si una función no devuelve ningún valor, con un tipo de devolución válido, ¿está bien que el compilador tire basura?

Por ejemplo,

int func1() { 
    return; // error 
} 

int func2() { 
    // does not return anything 
} 

El segundo func2 debería producir un error, pero no es así. ¿Hay alguna razón para ello? Mi pensamiento era tal que, se puede ver como un valor no inicializado, por lo que si tenemos que tirar un error en el segundo caso, entonces tenemos que tirar de error, si un valor es inicializado, por ejemplo

int i; // error 
    int i = 6; // okay 

Cualquier pensamientos, o esta es una pregunta duplicada? Aprecio tu ayuda.

+2

¿Es C o C++? ¿Obtiene errores o advertencias del compilador? ¿Qué compilador estás usando? – littleadv

+1

Sube tus advertencias. –

+0

posible duplicado de [opciones gcc: advertencia sobre funciones no vacías sin una declaración de retorno] (http://stackoverflow.com/questions/9924570/gcc-options-warning-on-non-void-functions-without-a- return-statement) –

Respuesta

15

En C++, tales código ha definido:

[stmt.return]/2 ... que fluye fuera del extremo de una función es equivalente a un retorno sin valor; esto da como resultado un comportamiento indefinido en una función que devuelve valor. ...

La mayoría de los compiladores mostrarán un código de advertencia similar al de la pregunta.

El estándar C++ no requiere que esto sea un error de tiempo de compilación porque en el caso general sería muy difícil determinar correctamente si el código realmente se ejecuta al final de la función, o si la función se cierra a través de una excepción (o un mecanismo longjmp o similar).

Considere

int func3() { 
    func4(); 
} 

Si func4() tiros, a continuación, este código es totalmente bien. Es posible que el compilador no pueda ver la definición de func4() (debido a la compilación por separado), por lo que no puede saber si lanzará o no.

Además, incluso si el compilador puede demostrar que func4() no arroja, todavía tendría que demostrar que func3() realmente se llama antes de que pueda rechazar legítimamente el programa. Tal análisis requiere la inspección de todo el programa, que es incompatible con la compilación por separado, y que ni siquiera es posible en el caso general.

+2

Muchos lenguajes incluyendo C# y Java requerirían una declaración 'return someValue;' en el ejemplo anterior, aunque nunca podría ser ejecutado. El diseño del lenguaje tiene que ver con las compensaciones y el valor relativo de los diagnósticos útiles frente a la necesidad ocasional de un código tonto para apaciguar a un compilador. No estoy de acuerdo con muchas de las decisiones de Java/C#, pero esta en particular no tengo ningún reparo. – supercat

+1

@supercat: Mi respuesta debe interpretarse como: "C++ realiza este comportamiento indefinido, pero desafortunadamente, eso no es suficiente para que los compiladores rechacen realmente este código, porque es imposible (en tiempo de compilación) detectar (perfectamente) si o no, se produce el comportamiento indefinido real ". Esto no quiere decir que sea imposible diseñar un lenguaje diferente que rechace de manera conservadora los programas que * podrían * ser válidos pero que no encajan en el modelo de seguridad del sistema de tipos de ese idioma (que C++ ya lo hace, para otras cosas) . – Mankarse

4

En C, en realidad es legal que una función no nula termine sin devolver un valor, , siempre que el código de llamada no intente utilizar el valor de retorno.

Por otro lado, una declaración return sin una expresión no puede aparecer en una función no nula.

Las partes pertinentes de la norma C99 están §6.9.1 para el primer caso: se alcanza

Si el } que termina una función, y el valor de la llamada función es utilizada por la persona que llama , el comportamiento no está definido.

y §6.8.6.4 para el segundo caso:

Una declaración return sin una expresión sólo estarán presentes en una función cuyo tipo de retorno es void.

+0

El primer párrafo es correcto para C, pero no para C++. –

+1

@KeithThompson: Es por eso que comencé con "In C ..." – caf

+0

No estoy seguro de cómo me lo perdí. (Pero la pregunta fue etiquetada tanto en C como en C++). –

2

Ambas funciones están mal formadas. La diferencia entre ellos es que su func1 infringe las reglas sobre cómo se puede usar la declaración return mientras que su func2 es un comportamiento indefinido. La instrucción return en su func1 es ilegal y una implementación debe diagnosticar esto. La falta de una declaración de devolución en su func2 es un comportamiento indefinido. La mayoría de los compiladores diagnosticarán esto, pero ninguno tiene que hacerlo. comportamiento

+0

En C, la primera función no está mal formada. El comportamiento solo está indefinido si la persona que llama realmente intenta usar el valor de retorno. – caf

+0

Sí, estoy de acuerdo, esto es más una prueba y tratando de descubrir por qué los comités C tienen esto ... – howtechstuffworks

9

En C, citando N1256 6.9.1p12:

Si se alcanza el } que termina una función, y el valor de la llamada función es utilizada por la persona que llama, el comportamiento es indefinido.

Así es legal (pero una mala idea) para una función no nula a no logran devolver un valor, pero si lo hace y la persona que llama intenta utilizar el resultado, el comportamiento no está definido. Tenga en cuenta que no necesariamente devuelve un valor arbitrario; en lo que respecta al estándar, todo es posible.

Pre-ANSI C no tenía la palabra clave void, por lo que la forma de escribir una función que no devolvía un valor era omitir el tipo de devolución, lo que devuelve implícitamente int. Requerir una instrucción return en una función de devolución de valor habría roto el código anterior. También habría requerido un análisis adicional por parte del compilador para determinar que todas las rutas de códigos alcancen una declaración return; dicho análisis es razonable para los compiladores modernos, pero podría haber sido una carga excesiva cuando C se estandarizó por primera vez.

C++ es un poco más estricto. En C++:

que fluye fuera del extremo de una función es equivalente a una retorno con ningún valor; esto da como resultado un comportamiento indefinido en una función de devolución de valor .

por lo que el comportamiento no está definido si la persona que llama intenta utilizar el resultado (inexistente) o no.

C y C++ compiladores duda pueden advertir sobre la falta return declaraciones, o sobre las rutas de control que caen fuera de la final de una función sin ejecutar una declaración return, pero las normas respectivas no les obligan a hacerlo.

+2

Tal análisis es solo razonable en casos simples: en casos complejos, el compilador podría no tener suficiente información disponible para saber que siempre llegará a una declaración 'return'. – caf

+0

Sería posible requerir que todas las rutas de control posibles ejecuten una declaración 'return'; Creo que C# lo hace. Por ejemplo, '{if (1) {return 42; } else {puts ("No devolver aquí"); } 'violaría tal requisito, aunque en realidad no es posible evitar el 'retorno'. C y C++ simplemente no hacen eso. –

+0

@Keith: No es factible. Ver la respuesta de Mankarse. –

Cuestiones relacionadas