Todo programa en C++ tiene principio en una función denominada main, en la función irá el código principal del programa y normalmente llamará a funciones especializadas para realizar las actividades para las que ha sido diseñado; y normalmente es el punto de término del programa, sin embargo es posible que el programa termine en otros puntos o funciones por diversas razones (excepciones, errores, uso de exit, etc.)
Hasta ahora se ha utilizado una versión simplificada de main,
int main()
es momento de revisar esta función en detalle.
main(int argc, char *argv[ ], char *envp[ ] ) { // Programa return 0; }
en donde,
argc – argument count: Valor no negativo que indica el número de argumentos enviados al programa desde el entorno donde se ejecuta. El primer argumento siempre será el nombre del programa, de modo que si llamamos al programa sin argumentos, argc, siempre valdrá 1
argv – argument vector: Puntero al primer elemento de una matriz de punteros a cadenas de texto terminadas en nulo que representan los argumentos pasados al programa desde el entorno de ejecución (argv[0] hasta argv[argc-1]). Se garantiza que el valor argv[argc] es un puntero nulo.
envp – que apunta a una matriz de punteros a variables de entorno de ejecución.
Nota: argc, argv, envp, son nombres arbitrarios y pueden llevar cualquier otro nombre//programa – Aquí van las sentencias del programa. return – Valor de retorno, el cual debe ser entero, normalmente si se devuelve 0 se supone que el programa termina normalmente. Si se omite por default el compilador devuelve 0 como valor de retorno.
De este modo el programa mínimo que podemos escribir en C++ pasa por declarar la función main sin sentencias, declaracón de tipos ni llamadoa otras funciones, incluso sin valor de retorno.
// main.cpp // Declaración de la función main // Además declara el programa mínimo que podemos hacer en C++ // 2019, Por http://about.me/carlosgbr // Versión 1 // Compilado en https://www.onlinegdb.com/online_c++_compiler int main( int argc, const char* argv[] ) { }
El ejecutar este programa obtendrás una salida aparentemente nula, aunque por “atrás” ocurren cosas interesantes que por ahora pasaré por alto.
Si haz utilizado algún programa por línea de comandos tal vez haz utilizado instrucciones tal vez parecidas a esto:
dir /o
ls -l
Los argumentos /o en el caso de dir y -l en el caso de ls, los podemos utilizar como parámetros que se pasan a nuestro programa desde la línea de comandos. Revisa el siguiente ejemplo.
// main2.cpp // Uso de parámetros en main // 2019, Por http://about.me/carlosgbr // Adaptado de Default int main arguments in C/C++ en // https://stackoverflow.com/questions/17045493/default-int-main-arguments-in-c-c // Versión 1 // Compilado en https://www.onlinegdb.com/online_c++_compiler #include <iostream> int main( int argc, const char* argv[] ) { // Imprime cada argumento de la línea de comandos. for( int i = 0; i < argc; i++ ) { std::cout << "Argumento "<< i << " = " << argv[i] << std::endl; } }
Si ejecutas este programa sin ningún parámetro (lo ejecutas y ya, tal como ha sido con todos los programas hasta ahora) obtendrás la siguiente salida.
Si deseas pasar parámetros al programa primero debes revisar el entorno de programación que utilizas, si estás trabajando con Dev-C o con CodeBlocks, por ejemplo, debes generar un ejecutable y ejectuarlo desde la línea de comando para que puedas llamar al programa con parámetros.
Si tu compilador es en línea, normalmente el entorno te proporcionará un mecanismo para pasar parámetros a tu programa, en nuestro caso que utilizamos OnlineGDB antes de ejecutar el programa podemos escribir los parámetros en la ventana input, como puedes apreciar en la siguiente imagen.
Lo cual es equivalente a llamar a nuestro programa desde la línea de comando escribiendo:
nombreprograma Argumento1 Argumento2
y obtendremos la siguiente salida
La función main tiene varias propiedades especiales (1)(2) :
Hay más propiedades que he pasado por alto, en etapa no representa ningún problema no considerarlas.
Antes de que se ejecuten las sentencias que programamos, ya han ocurrido muchas cosas que preparan el entorno de ejecución de nuestros programas, como pueden ser la carga del programa, la inicialización de variables estáticas y algunas verificaciones de hardware, tras este proceso se pasa el control del programa a una función que debe llamarse main, y aquí es donde como programadores tomamos el control.
Si la función main llama a una función, main pasa el control a dicha función, cuando termina la ejecución de la función ésta devuelve el control a main cuando encuentra la sentencia return o cuando el código de la función termina. También recuerda que puedes terminar el programa en cualquier punto utilizando la función exit de la librería estándar.
Si el compilador encuentra la sentencia return, la utiliza como última instrucción. Como ya se ha mencionado, normalmente se devuelve un 0, este valor se entrega a quien llamó al programa, normalmente el sistema operativo. Nosotros podemos en caso de ser necesario definir un valor o conjunto de valores de salida para return.
Si no se declara una sentencia return, el compilador devolverá 0, indicando que todo salió bien.
Aunque normalmente un código de salida 0 significa que todo salió bien, puede darse la situación que una determinada plataforma o compilador realicen una interpretación del 0 y para algún caso particular 0 no signifique necesariamente “sin novedad”. Para evitar este tipo de situaciones C++ recomienda que utilices las macros EXIT_FAILURE y EXIT_SUCCESS
Valor de return | Comentarios |
EXIT_FAILURE | Devuelve una ejecución errónea |
EXIT_SUCCESS | indica al proceso padre que todo ha salido bien |
Entero | Definido por el programador para determinar una condición específica |
Termino con un sencillo programa que utiliza la tabla anterior para indicar algunas condiciones específicas de salida y no la predeterminada (return 0)
// cpp_68_main_return.cpp // Uso de parámetros en main como forma de recepción de datos // para ilustrar diversas condiciones de salida de return // El programa calcula el índice de masa corporal // 2019, Por http://about.me/carlosgbr // Versión 1 // Compilado en https://www.onlinegdb.com/online_c++_compiler #include <iostream> #include <sstream> using namespace std; // Este programa requiere obligatoriamente 3 argumentos de entrada // modo de llamada: nombreprograma nombre estatura peso // nombreprograma - el nombre del programa sin espacios varía como lo llames, dejar espacio // nombre - tu nombre, dejar espacio // peso - en kilogramos, dejar espacio // estatura - en metros // ejemplo: imc paulina 51 164 int main(int argc, const char* argv[]) { // Verificamos que tenga los 3 parámetros obligatorios if (argc != 4) { std::cout << "Número de parámetros incorrecto."; return EXIT_FAILURE; // Terminamos el programa } else { // Recuperamos los parámetros de la línea de comandos string nombre = argv[1]; // El primero es el nombre del usuario // Convertimos el peso en número string speso = argv[2]; // Toma el segundo argumento y lo almacena istringstream stream1(speso); float peso; stream1 >> peso; // hacemos la conversión a float // convertimos estatura a float string sestatura = argv[3]; istringstream stream2(sestatura); float estatura; stream2 >> estatura; // Calculamos nuestro índice de masa corporal, estatura en metros // peso en kilogramos. float imc = peso / (estatura*estatura); // Definimos nuestroc xódigos de retorno de a cuerdo a nuestra // conveniencia, recuerda nosotros somos los responsables // Una vez depurado puedes comentar las salidas cout if (imc > 16) { cout << nombre << " tu imc es: " << imc; return EXIT_SUCCESS; // Fin de programa, correcto } else if ((imc <= 16) and (imc > 10)) { cout << nombre << " tu imc es: " << imc; return 10; // nosotros definimos que significa 1, por // ejemplo "revisar valores" } else if ((imc <= 10) and (imc > 0)) { cout << nombre << " tu imc es: " << imc; return 20; // Revisar sino están invertidos los argumentos } else { cout << nombre << " tu imc es: " << imc; return 30; // Error desconocido } } cout << "Hola Mundo"; //Esta línea no debería ejecutarse dado que el // programa termina en return. }
En el programa anterior (cpp_68_main_return.cpp) hacemos una variante del programa de cálculo del IMC (Índice de masa corporal) en este caso solo nos interesa el valor del IMC no su interpretación como fue en el programa cpp_20_imc2if.cpp, además por las características del diseño, únicamente nos interesan (realmente) los códigos de retorno que nosotros definimos en función del resultado obtenido. Naturalmente, es un programa simplificado cuyo objetivo es mostrar como puedes implementar y utilizar return, el resto del programa es solo un modo de obtener códigos de salida útiles.
Para que nuestro programa funcione de forma correcta, requiere que le pases 3 argumentos, nombre, peso, estatura, si alguno falta el programa se detiene y termina utilizando la macro EXIT_FAILURE y envía un mensaje. Nota que validamos el número de valores introducidos con if. (Ahora responde, ¿Porqué validamos 4 argumentos y no 3? si no encuentras la respuesta, revisa nuevamente este documento más arriba).
En esta imagen vemos una salida si alimentamos la entrada con el número incorrecto de argumentos:
Por otra parte nuestro programa espera los datos de una forma muy específica, peso en kilogramos (el usuario los podría poner en gramos), la estatura en metros (podrían ponerlo en centímetros dado que muchas calculadoras así lo usan). Como el programa de cualquier forma realizará un cálculo, es nuestra responsabilidad controlar el resultado e informar en medida de lo posible de potenciales errores, para esto utilizamos los códigos de salida con return. Nosotros en la documentación podemos indicar al usuario que al obtener un código de salida 30, por ejemplo, que revisen que no haya puesto a 0 algún valor.
A continuación te muestro varias corridas del programa con diferentes argumentos y su respectiva salida.
Parámetros de entradacalculaimc Carlos 75 1.68Salida Parámetros de entrada
calculaimc Carlos 1.68
Salida Parámetros de entrada calculaimc Carlos 0 1.68
Salida Concluyo esta sección mencionando que entre más condiciones de error quieras manejar y resolver de forma apropiada (y no simplemente decir “exit code 30 – Error desconocido) requieres codificar más variantes, de hecho todas las que quieras manejar: Evitar texto en los campos numéricos, tratamiento de cifras negativas, cifras que tengan caracteres y números I en lugar de 1, O en lugar de cero, por ejemplo.
Termino este capítulo abordando una pregunta que suele ser recurrente de tiempo en tiempo. El tipo utilizado con mai().
Seamos concretos y tajantes, utilizar void main() es incorrecto, no lo utilices aunque el compilador que utilices te lo permita, el estándar actual y los compiladores modernos rechazarán el uso de
void con main() // Erróneo
El estándar actual requiere que main devuelva un entero, por tanto esta es la forma correcta de tipar a main(). El int devuelto por main() se devuelve al sistema que lo invoca, ya sea el sistema operativo u otro programa. Sino se invoca un valor de retorno, el valor de retorno se ignora. Por esta razón algunos programadores creen que el uso de void es adecuado.
Para zanjar esta posible controversia por parte de algunos usuarios que puedan utilizar void, tomo las palabras de Bjarne Stroustrup en su blog en la sección de preguntas y respuestas:
“Incluso si su compilador acepta “void main()” evítelo, o arriesgue siendo considerado ignorante por los programadores C y C++.”
“Even if your compiler accepts “void main()” avoid it, or risk being considered ignorant by C and C++ programmers. ” Bjarne Stroustup.
int main() // Correcto
La mayoría de los compiladores aceptará esta forma, de forma automática se asigna un valor de retorno int a main(), sin embargo es preferible que utilices la forma formal int main()
int main() // Correcto, preferible int main()
En este caso no hay una regla definida, muchos entornos de desarrollo al iniciar la plantilla de un programa nuevo ya los incluyen, por lo que normalmente no nos ocupamos de este tema, sin embargo si los debes escribir manualmete, puedes omitirlos sino utilizas los argumentos en tu programa. Naturalmente siempre será mejor que te adhieras a los estándares, así que si insistieras en un respuesta, la sugerencia es que utilices la forma completa.
int main (int argc, const char* argv[])
Hay mucho más que se puede explorar de la fución main, sin embargo ya tienes un bosquejo inicial que te ilustra que main es más que un simple contenedor de código, tiene muchas características que podemos explotar aún en programas incluso básicos, si vas a programar utilerías, algunos exploits o cosas… “interesantes” te será de utilidad conocer y practicar el paso y uso de argumentos con main.
Así cierro el bloque dedicado a funciones. He intentado ofrecerte la estructura que te servirá para que con paso seguro puedas explorar y ampliar el universo que implican las funciones en C++. Recuerda entre más aprendemos, menos sabemos… pero podemos hacer más 😉
Funciones VI en C++ by Roberto C. González is licensed under a Creative Commons Reconocimiento-NoComercial-CompartirIgual 4.0 Internacional License.
El comando dnsenum es una herramienta de línea de comandos para realizar enumeración de DNS…
En esta entrada te presento 24 de las listas negras más comunes que los servidores…
ZoomIt es una herramienta de anotación y zoom de pantalla para presentaciones técnicas que incluyen…
WinObj es el visor de espacios de nombres de Object Manager definitivo. Es la primera…
Whois realiza el registro de registro para el nombre de dominio o la dirección IP…
VolumeID – Esta utilidad, le permite cambiar los identificadores de los discos FAT y NTFS…