Acabo de encontrar el código C de alguien que me confunde por qué está compilando. Hay dos puntos que no entiendo.
Primero, el prototipo de la función no tiene parámetros en comparación con la definición de la función real. En segundo lugar, el parámetro en la definición de la función no tiene un tipo.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
¿Por qué funciona esto? Lo he probado en un par de compiladores y funciona bien.
c
parameters
function-prototypes
function-parameter
AdmiralJonB
fuente
fuente
-Wstrict-prototypes
tanto para elint func()
yint main()
: xc: 3: advertencia: la declaración de función no es un prototipo. Usted debe declararmain()
comomain(void)
así.int func();
es compatible conint func(arglist) { ... }
.int main(void)
.Respuestas:
Todas las otras respuestas son correctas, pero solo para completar
Y de nuevo por el bien de la integridad. De la especificación C11 6: 11: 6 (página: 179)
fuente
En C
func()
significa que puede pasar cualquier número de argumentos. Si no desea argumentos, debe declarar comofunc(void)
. El tipo que está pasando a su función, si no se especifica de manera predeterminadaint
.fuente
func(42,0x42);
(donde todas las llamadas deben usar la forma de dos argumentos).unsigned
es solo otro nombre para el mismo tipo queunsigned int
.int func();
es una declaración de función obsoleta de los días en que no existía el estándar C, es decir, los días de K&R C (antes de 1989, año en que se publicó el primer estándar "ANSI C").Recuerde que no había prototipos en K&R C y que la palabra clave
void
aún no se había inventado. Todo lo que podía hacer era decirle al compilador sobre el tipo de retorno de una función. La lista de parámetros vacía en K&R C significa "un número de argumentos no especificado pero fijo". Fijo significa que debe llamar a la función con el mismo número de argumentos cada vez (a diferencia de una función variada comoprintf
, donde el número y el tipo pueden variar para cada llamada).Muchos compiladores diagnosticarán esta construcción; en particular
gcc -Wstrict-prototypes
le dirá "la declaración de función no es un prototipo", lo cual es perfecto, porque parece un prototipo (¡especialmente si está envenenado por C ++!), pero no lo es. Es una declaración de tipo de devolución K&R C de estilo antiguo.Regla general: nunca deje vacía una declaración de lista de parámetros vacía, utilice
int func(void)
para ser específico. Esto convierte la declaración de tipo de retorno de K&R en un prototipo C89 adecuado. Los compiladores están contentos, los desarrolladores están contentos, los verificadores estáticos están contentos. Sin embargo, los que confunden con ^ W ^ Wfond de C ++ pueden encogerse, ya que necesitan escribir caracteres adicionales cuando intentan ejercer sus habilidades de idioma extranjero :-)fuente
int
.Sin embargo, consideraría que cualquier compilación que pase esto carece de un nivel de advertencia / error configurado, no tiene sentido permitir que esto permita el código real.
fuente
Es la declaración y definición de la función de estilo K&R . Del estándar C99 (ISO / IEC 9899: TC3)
Sección 6.7.5.3 Declaradores de funciones (incluidos los prototipos)
Sección 6.11.6 Declaradores de funciones
Sección 6.11.7 Definiciones de funciones
Lo que significa que el viejo estilo de K & R estilo
Ejemplo:
Declaración:
int old_style();
Definición:
fuente
C asume
int
si no se proporciona ningún tipo en el tipo de retorno de función y la lista de parámetros . Solo para esta regla es posible seguir cosas extrañas.Una definición de función se ve así.
Si es un prototipo que escribes
En prototype solo puede especificar el tipo de parámetros. El nombre de los parámetros no es obligatorio. Entonces
Además, si no especifica el tipo de parámetro pero el nombre
int
se asume como tipo.Si vas más lejos, seguir funciona también.
El compilador asume
int func()
cuando escribesfunc()
. Pero no coloquefunc()
dentro de un cuerpo funcional. Esa será una llamada a funcionesfuente
int func()
No es una forma implícita deint func(int)
.Como se dijo en @ Krishnabhadra, todas las respuestas anteriores de otros usuarios tienen una interpretación correcta, y solo quiero hacer un análisis más detallado de algunos puntos.
En el Old-C como en ANSI-C, el " parámetro formal sin tipo ", tome la dimensión de su registro de trabajo o capacidad de profundidad de instrucción (registros sombra o ciclo acumulativo de instrucción), en una MPU de 8 bits, será un int16, en un 16 bits MPU y así será un int16 y así sucesivamente, en el caso de arquitecturas de 64 bits pueden optar por compilar opciones como: -m32.
Aunque parezca una implementación más simple a alto nivel, para pasar múltiples parámetros, el trabajo del programador en el paso de tipo de datos de control dimencion, se vuelve más exigente.
En otros casos, para algunas arquitecturas de microprocesadores, los compiladores ANSI personalizados, aprovecharon algunas de estas características antiguas para optimizar el uso del código, forzando la ubicación de estos "parámetros formales sin tipo" para trabajar dentro o fuera del registro de trabajo, hoy usted obtiene casi lo mismo con el uso de "volátil" y "registro".
Pero debe tenerse en cuenta que los compiladores más modernos, no hacen ninguna distinción entre los dos tipos de declaración de parámetros.
Ejemplos de una compilación con gcc en linux:
En cualquier caso, la declaración del prototipo localmente no sirve de nada, porque no hay llamada sin parámetros, la referencia a este prototipo será negligente. Si utiliza el sistema con "parámetro formal sin tipo", para una llamada externa, proceda a generar un tipo de datos de prototipo declarativo.
Me gusta esto:
fuente
int
, que generalmente es el tamaño del registro de trabajo o 16 bits, lo que sea menor.int
tipo que no sea capaz de mantener todos los valores en el rango: 32767 a +32767 (no se requiere la nota -32768) y también es capaz de contener todos loschar
valores (lo que significa que sichar
tiene 16 bits, debe estar firmado oint
debe ser más grande).Con respecto al tipo de parámetro, ya hay respuestas correctas aquí, pero si desea escucharlo desde el compilador, puede intentar agregar algunas banderas (las banderas son casi siempre una buena idea de todos modos).
compilando su programa usando
gcc foo.c -Wextra
consigo:extrañamente
-Wextra
no capta esto porclang
(no reconoce-Wmissing-parameter-type
por alguna razón, tal vez por los históricos mencionados anteriormente) pero-pedantic
sí:Y para el problema del prototipo, como se dijo anteriormente, se
int func()
refiere a parámetros arbitrarios a menos que lo defina explícitamente como loint func(void)
que le daría los errores como se esperaba:o en
clang
como:fuente
Si la declaración de la función no tiene parámetros, es decir, está vacía, entonces está tomando un número no especificado de argumentos. Si desea que no tome argumentos, cámbielo a:
fuente
Es por eso que normalmente aconsejo a las personas que compilen su código con:
Estas banderas imponen un par de cosas:
Estas banderas también se usan por defecto en muchos proyectos de código abierto. Por ejemplo, FreeBSD tiene estas banderas habilitadas cuando compila con WARNS = 6 en su Makefile.
fuente