2010-04-21 15 views
19

Hoy, mirando a la página del manual de open(), me he dado cuenta de esta función está 'sobrecargado':sobrecarga de funciones en C

int open(const char *pathname, int flags); 
    int open(const char *pathname, int flags, mode_t mode); 

yo no pensaba que es posible en C. ¿Cuál es el 'truco' para lograr esto?

de editar posteriormente:
así que no es realmente una sobrecarga, ya que al utilizar varargs - sólo se puede suministrar múltiples argumentos del mismo tipo. Entonces, ¿está mode_t detrás de las escenas?

+0

mode_t es de hecho un entero, pero se puede suministrar argumentos de diferentes tipos, en el supuesto de que sabe cómo interpretarlas. La familia de funciones printf hace esto, utilizando la cadena de formato para saber cómo interpretar sus argumentos adicionales, incluso cuando se escriben de manera diferente. Mi respuesta a continuación tiene algunos ejemplos que podrían aclarar esto. –

+0

@Eli gracias, debo haber confundido eso con Java. –

+0

Las funciones como esta se llaman funciones variadas. – Chris

Respuesta

30

Se trata de utilizar variable arguments. Esas declaraciones aparecen solo en la página man, ya que esas 2 son las únicas formas en que debe llamar a open(). La función C real se declarará como p.

int open(const char *pathname,int flags,...); 

Con argumentos variables, los argumentos no necesitan ser del mismo tipo. printf es el ejemplo obvio de esto.

En el caso de open(), el primer argumento de variable debe ser mode_t si 'flags contiene el indicador O_CREAT porque la implementación de open() espera que sea mode_t (que detrás de escena probablemente sea unsigned int o unsigned de largo - pero eso no tiene nada que ver con varargs)

3

respuesta muy corta - varargs

+0

e imita a los votos abajo para respuestas correctas - la concisión es una virtud. – KevinDTimm

2

que se puede fingir utilizando la lista de argumentos variable, con ...

int function(int x, ...); 
6

"modo debe especificarse cuando se O_CREAT está en las banderas, y se ignora lo contrario"

extern int open (__const char *__file, int __oflag, ...)

Utiliza varargs y sólo carga la variable modo de argumento si __oflag contiene O_CREAT.

10

C hace que sea posible escribir la función con un variable number of argument, como printf.

Dicho esto, no existe una forma confiable y multiplataforma en C para escribir una función que toma exactamente 2 o 3 argumentos; en general, debe hacer algo como

some_function(5, 6, 7, NULL); 
some_function(5, 6, 8, 2, 5, NULL); 

En otras palabras, debe tener un argumento "final" de terminación. Como alternativa, puede incluir el número de parámetros de alguna manera en un parámetro anterior, como

another_func(2, "hello", "world"); 
another_func(3, "goodbye", "cruel", "world"); 

El printf familia de funciones de toma este enfoque; el primer parámetro de formato contiene el número de parámetros adicionales necesarios; p.ej. con printf("%f %f", 5.6, 7.11), sabe que debe haber 2 parámetros de flotación. Sin embargo, esto sería algo inseguro en una función de biblioteca definida por el usuario, ya que si dijera my_printf("%s %f %f %f %s", 5.6), podría obtener segfaults o algo peor. Afortunadamente, la mayoría de los compiladores C verificarán sus llamadas al printf en tiempo de compilación para evitar este tipo de problema.

En el caso de open, la función se declara como que tiene argumentos variables, y el tercer parámetro solo se marca si se establece O_CREAT. Entonces, así es como "con seguridad" determina si un tercer argumento está presente. Puse "de manera segura" entre comillas porque técnicamente no hay forma de que Open sepa en tiempo de ejecución cuántos parámetros se pasaron realmente. Por ejemplo, las siguientes llamadas se compilan sin errores o advertencias:

open("foo.txt", 5, "not an integer", 7); // extra and invalid parameters 
open("bar.txt", O_CREAT);     // third parameter is missing 
+1

Si 'some_function()' toma 'int's, no debe terminar con' NULL', ya que 'NULL' es solo 0 en el contexto numérico. Los terminadores 'NULL' funcionan mejor con parámetros de puntero. –

+0

@Chris: Buen punto, generalmente uso NULL como el terminador independientemente de los tipos de datos, pero tienes razón de que podría ser confuso, especialmente para las personas que no saben que 0 y NULL son lo mismo, ya que podrían pensar podrían escribir algo como 'some_func (3, 2, 1, 0, -1, NULL)' cuando de hecho esto haría que 0 actuara como el parámetro de terminación. –

+1

Las versiones recientes de gcc y los encabezados glibc juntos generarán una advertencia para sus dos últimos ejemplos. – caf