valores sirve significado sentencia retornan que para funciones ejemplo comando c++ visual-studio-2012 c++11 methods

c++ - sirve - significado de int main()



¿Por qué esta compilación de fragmentos de C++(función no nula no devuelve un valor) (7)

Como ya se mencionó, este es un comportamiento indefinido y le dará una advertencia del compilador. La mayoría de los lugares en los que he trabajado requieren que active las configuraciones del compilador para tratar las advertencias como errores, lo que obliga a que todo su código compile con 0 errores y 0 advertencias. Este es un buen ejemplo de por qué es una buena idea.

Encontré esto en una de mis bibliotecas esta mañana:

static tvec4 Min(const tvec4& a, const tvec4& b, tvec4& out) { tvec3::Min(a,b,out); out.w = min(a.w,b.w); }

Esperaría un error del compilador porque este método no devuelve nada y el tipo de devolución no es void .

Las únicas dos cosas que vienen a la mente son

  • En el único lugar donde se llama este método, el valor de retorno no se está utilizando o almacenando. (Se suponía que este método era void : el tipo de retorno tvec4 es un error de copiar y pegar)

  • se está creando un tvec4 construido por defecto, que parece un poco diferente, oh, todo lo demás en C ++.

No he encontrado la parte de la especificación C ++ que aborda esto. Las referencias (ha) son apreciadas.

Actualizar

En algunas circunstancias, esto genera un error en VS2012. No he reducido detalles, pero es interesante, no obstante.


Compila tu código con la opción -Wreturn-type :

$ g++ -Wreturn-type source.cpp

Esto te dará una advertencia . Puede convertir la advertencia en error si usa -Werror también:

$ g++ -Wreturn-type -Werror source.cpp

Tenga en cuenta que esto convertirá todas las advertencias en errores. Entonces, si quiere un error para una advertencia específica, diga -Wreturn-type , simplemente escriba return-type sin -W parte como:

$ g++ -Werror=return-type source.cpp

En general, siempre debe usar la opción de " -Wall , que incluye las advertencias más comunes, esto también incluye la declaración de devolución faltante. Junto con -Wall , puede usar -Wextra también, que incluye otras advertencias no incluidas por -Wall .


Este es un comportamiento indefinido del borrador de la sección estándar 6.6.3 de la C + + 11. El párrafo 2 de la declaración de retorno que dice:

[...] Fluir fuera del final 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. [...]

Esto significa que el compilador no está obligado a proporcionar un error ni una advertencia por lo general porque puede ser difícil de diagnosticar en todos los casos. Podemos ver esto a partir de la definición de comportamiento indefinido en el borrador del estándar en la sección 1.3.24 que dice:

[...] El comportamiento indefinido permitido abarca desde ignorar completamente la situación con resultados impredecibles, hasta comportarse durante la traducción o la ejecución del programa de una manera documentada característica del entorno (con o sin la emisión de un mensaje de diagnóstico), hasta terminar una traducción o ejecución (con la emisión de un mensaje de diagnóstico). [...]

Aunque en este caso podemos obtener tanto gcc como clang para generar un wanring usando la bandera de " -Wall , lo que me da una advertencia similar a esta:

advertencia: el control llega al final de la función no nula [-Wreturn-type]

Podemos convertir esta advertencia particular en un error utilizando el -Werror=return-type . También me gusta usar -Wextra -Wconversion -pedantic para mis propios proyectos personales.

Como ComicSansMS menciona en Visual Studio, este código generaría C4716 que es un error por defecto, el mensaje que veo es:

error C4716: ''Min'': debe devolver un valor

y en el caso donde no todas las rutas de código devolverían un valor, generaría C4715 , que es una advertencia.


Esto es más de la regla / característica estándar de C ++ que tiende a ser flexible con las cosas y que tiende a ser más cercana a C.

Pero cuando hablamos de los compiladores, GCC o VS, son más para uso profesional y para una variedad de propósitos de desarrollo y, por lo tanto, establecen reglas de desarrollo más estrictas según sus necesidades.

Eso también tiene sentido, mi opinión personal, porque el lenguaje tiene que ver con las características y su uso, mientras que el compilador define las reglas para una mejor y óptima forma de usarlo según sus necesidades.

Como se mencionó en la publicación anterior, el compilador a veces da el error, a veces da advertencia y también tiene la opción de saltarse estas advertencias, etc., lo que indica la libertad de utilizar el idioma y sus características de la manera que mejor se adapte a nosotros.


Junto con esto, hay varias otras preguntas que mencionan este comportamiento de devolver un resultado sin tener una declaración de return . Un ejemplo simple sería:

int foo(int a, int b){ int c = a+b;} int main(){ int c = 5; int d = 5; printf("f(%d,%d) is %d/n", c, d, foo(c,d)); return 0; }

Podría esta anomalía ser debido a las propiedades de la pila y más específicamente:

Máquinas de dirección cero

En máquinas con dirección cero, se supone que las ubicaciones de ambos operandos están en una ubicación predeterminada . Estas máquinas usan la pila como fuente de los operandos de entrada y el resultado vuelve a la pila. Stack es una estructura de datos LIFO (último en entrar, primero en salir) compatible con todos los procesadores, sean o no máquinas de dirección cero. Como su nombre lo indica, el último elemento colocado en la pila es el primer elemento que se saca de la pila. Todas las operaciones en este tipo de máquina suponen que los operandos de entrada requeridos son los dos valores superiores en la pila. El resultado de la operación se coloca en la parte superior de la pila.

Además de eso, para acceder a la memoria para leer y escribir datos, los mismos registros se utilizan como fuente de datos y destino (registro DS (segmento de datos)), que almacenan primero las variables necesarias para el cálculo y luego el resultado devuelto.

Nota:

Con esta respuesta me gustaría discutir una posible explicación del comportamiento extraño en el nivel de la máquina (instrucción) ya que ya tiene un contexto y está cubierto en un rango suficientemente amplio.


Tal vez alguna elaboración adicional sobre el por qué de la pregunta.

C ++ se diseñó para que un gran cuerpo de código de cuerpo preexistente compilara con una cantidad mínima de cambios. Desafortunadamente, C sí mismo estaba pagando un deber similar al primer C pre-estándar que ni siquiera tenía la palabra clave void y en su lugar se basó en un tipo de retorno predeterminado de int . Las funciones C generalmente devolvían valores, y cada vez que se escribía un código superficialmente similar a los procedimientos Algol / Pascal / Básico sin declaraciones de return , la función era, bajo el cofre, devolver la basura que quedaba en la pila. Ni el llamador ni el destinatario asignan el valor de la basura de manera confiable. Si la basura es ignorada por cada persona que llama, todo está bien y C ++ hereda la obligación moral de compilar dicho código.

(Si el llamador utiliza el valor devuelto, el código puede comportarse de manera no determinista, similar al procesamiento de una variable no inicializada. ¿Podría la diferencia ser identificada de forma fiable por un compilador, en un lenguaje sucesor hipotético para C? Esto es casi imposible. El llamador y el destinatario pueden estar en diferentes unidades de compilación).

La int implícita es solo una parte del legado de C involucrado aquí. Una función de "despachador" puede, según un parámetro, devolver una variedad de tipos de algunas ramas de código y no devolver ningún valor útil de otras ramas de código. Dicha función generalmente se declararía para devolver un tipo lo suficientemente largo como para contener cualquiera de los tipos posibles y la persona que llama podría necesitar echarlo o extraerlo de una union .

Así que la causa más profunda probablemente sea la creencia de los creadores del lenguaje C de que los procedimientos que no devuelven ningún valor son solo un caso especial sin importancia de funciones que sí lo hacen; este problema se agravó por la falta de foco en la seguridad del tipo de llamadas a funciones en los dialectos C más antiguos.

Mientras que C ++ rompió la compatibilidad con algunos de los peores aspectos de C ( example ), la voluntad de compilar una declaración de retorno sin un valor (o el retorno implícito sin valor al final de una función) no era uno de ellos.


Tal vez alguna explicación sobre el por qué de la pregunta:

Resulta que, en realidad, es bastante difícil † para un compilador de C ++ determinar si una función sale sin un valor de retorno. Además de las rutas de código que terminan en declaraciones explícitas de retorno y las que caen fuera del final de la función, también debe considerar posibles lanzamientos de excepción o longjmp s en la función en sí misma, así como en todas sus calles.

Si bien es bastante fácil para un compilador identificar una función que parece que le falta una devolución, es considerablemente más difícil probar que le falta una devolución. Con el fin de levantar a los proveedores de compiladores de esta carga, la norma no requiere que esto genere un error.

Por lo tanto, los proveedores de compiladores pueden generar una advertencia si están seguros de que a una función le falta una devolución y el usuario puede ignorar / enmascarar esa advertencia en los raros casos en que el compilador estuvo realmente equivocado.

†: En el caso general, esto es equivalente al problema de detención , por lo que es realmente imposible para una máquina decidir esto de manera confiable.