C Language
Lenguajes comunes de programación C y prácticas de desarrollador.
Buscar..
Comparando literal y variable
Supongamos que estás comparando valor con alguna variable
if ( i == 2) //Bad-way
{
doSomething;
}
Ahora supongamos que te has equivocado con ==
con =
. Entonces tomará su dulce momento para averiguarlo.
if( 2 == i) //Good-way
{
doSomething;
}
Luego, si se omite accidentalmente un signo igual, el compilador se quejará de un "intento de asignación a un literal". Esto no lo protegerá cuando compare dos variables, pero cada pequeña ayuda.
Vea aquí para más información.
No deje en blanco la lista de parámetros de una función - use void
Supongamos que está creando una función que no requiere argumentos cuando se le llama y se enfrenta al dilema de cómo debe definir la lista de parámetros en el prototipo de función y la definición de función.
Tiene la opción de mantener la lista de parámetros vacía tanto para el prototipo como para la definición. Por lo tanto, se ven igual que la declaración de llamada de función que necesitará.
Lees en alguna parte que uno de los usos de la palabra clave void (solo hay unos pocos), es definir la lista de parámetros de funciones que no aceptan ningún argumento en su llamada. Por lo tanto, esta es también una opción.
Entonces, ¿cuál es la elección correcta?
RESPUESTA: usando la palabra clave void
CONSEJOS GENERALES: Si un idioma proporciona cierta característica para usar con un propósito especial, es mejor que lo use en su código. Por ejemplo, usar enum
s en lugar de #define
macros (eso es para otro ejemplo).
C11 sección 6.7.6.3 "Declaradores de función", párrafo 10, establece:
El caso especial de un parámetro sin nombre de tipo void como el único elemento en la lista especifica que la función no tiene parámetros.
El párrafo 14 de esa misma sección muestra la única diferencia:
... Una lista vacía en un declarador de función que forma parte de una definición de esa función especifica que la función no tiene parámetros. La lista vacía en un declarador de función que no forma parte de una definición de esa función especifica que no se proporciona información sobre el número o los tipos de parámetros.
Una explicación simplificada provista por K&R (pgs- 72-73) para lo anterior:
Además, si una declaración de función no incluye argumentos, como en
double atof();
, eso también significa que no se debe asumir nada sobre los argumentos deatof
; Todas las comprobaciones de parámetros están desactivadas. Este significado especial de la lista de argumentos vacíos tiene la intención de permitir que los programas C más antiguos se compilen con compiladores nuevos. Pero es una mala idea usarlo con nuevos programas. Si la función toma argumentos, declararlos; Si no toma argumentos, usevoid
.
Así es como debería verse su prototipo de función:
int foo(void);
Y así es como debería ser la definición de la función:
int foo(void)
{
...
<statements>
...
return 1;
}
Una ventaja de usar el tipo de declaración anterior, sobre el tipo int foo()
(es decir, sin usar la palabra clave void ), es que el compilador puede detectar el error si llama a su función utilizando una declaración errónea como foo(42)
. Este tipo de declaración de llamada de función no causará ningún error si deja la lista de parámetros en blanco. El error pasaría en silencio, sin ser detectado y el código aún se ejecutaría.
Esto también significa que debe definir la función main()
esta manera:
int main(void)
{
...
<statements>
...
return 0;
}
Tenga en cuenta que aunque una función definida con una lista de parámetros vacía no toma argumentos, no proporciona un prototipo para la función, por lo que el compilador no se quejará si la función se llama posteriormente con argumentos. Por ejemplo:
#include <stdio.h>
static void parameterless()
{
printf("%s called\n", __func__);
}
int main(void)
{
parameterless(3, "arguments", "provided");
return 0;
}
Si ese código se guarda en el archivo proto79.c
, se puede compilar en Unix con GCC (la versión 7.1.0 en macOS Sierra 10.12.5 se usa para demostración) de esta manera:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -pedantic proto79.c -o proto79
$
Si compilas con opciones más estrictas, obtienes errores:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79
proto79.c:3:13: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
static void parameterless()
^~~~~~~~~~~~~
proto79.c: In function ‘parameterless’:
proto79.c:3:13: error: old-style function definition [-Werror=old-style-definition]
cc1: all warnings being treated as errors
$
Si le da a la función el prototipo formal static void parameterless(void)
, entonces la compilación genera errores:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79
proto79.c: In function ‘main’:
proto79.c:10:5: error: too many arguments to function ‘parameterless’
parameterless(3, "arguments", "provided");
^~~~~~~~~~~~~
proto79.c:3:13: note: declared here
static void parameterless(void)
^~~~~~~~~~~~~
$
Moraleja: siempre asegúrese de tener prototipos y asegúrese de que su compilador le diga cuándo no está obedeciendo las reglas.