usar tipos sirve realiza qué que por parametros para linea función funciones ejemplos como comandos c arguments default-value

sirve - tipos de funciones en c



C argumentos por defecto (19)

¿Por qué no podemos hacer esto?

Asigne un valor predeterminado al argumento opcional. De esa manera, la persona que llama a la función no necesariamente tiene que pasar el valor del argumento. El argumento toma el valor por defecto. Y fácilmente ese argumento se vuelve opcional para el cliente.

Por ejemplo

void foo (int a, int b = 0);

Aquí b es un argumento opcional.

¿Hay una manera de especificar argumentos predeterminados para una función en C?


Generalmente no, pero en gcc Puede hacer que el último parámetro de funcA () sea opcional con una macro.

En funcB () utilizo un valor especial (-1) para indicar que necesito el valor predeterminado para el parámetro ''b''.

#include <stdio.h> int funcA( int a, int b, ... ){ return a+b; } #define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 ) int funcB( int a, int b ){ if( b == -1 ) b = 8; return a+b; } int main(void){ printf("funcA(1,2): %i/n", funcA(1,2) ); printf("funcA(1): %i/n", funcA(1) ); printf("funcB(1, 2): %i/n", funcB(1, 2) ); printf("funcB(1,-1): %i/n", funcB(1,-1) ); }


Mejoré la answer Jens Gustedt para que:

  1. Las funciones en línea no se emplean
  2. los valores predeterminados se calculan durante el preprocesamiento
  3. macros reutilizables modulares
  4. posible establecer un error de compilación que coincida significativamente con el caso de argumentos insuficientes para los valores predeterminados permitidos
  5. los valores predeterminados no son obligatorios para formar la cola de la lista de parámetros si los tipos de argumentos no serán ambiguos
  6. interviene con C11 _Generic
  7. ¡Varíe el nombre de la función por el número de argumentos!

variadic.h:

#ifndef VARIADIC #define _NARG2(_0, _1, _2, ...) _2 #define NUMARG2(...) _NARG2(__VA_ARGS__, 2, 1, 0) #define _NARG3(_0, _1, _2, _3, ...) _3 #define NUMARG3(...) _NARG3(__VA_ARGS__, 3, 2, 1, 0) #define _NARG4(_0, _1, _2, _3, _4, ...) _4 #define NUMARG4(...) _NARG4(__VA_ARGS__, 4, 3, 2, 1, 0) #define _NARG5(_0, _1, _2, _3, _4, _5, ...) _5 #define NUMARG5(...) _NARG5(__VA_ARGS__, 5, 4, 3, 2, 1, 0) #define _NARG6(_0, _1, _2, _3, _4, _5, _6, ...) _6 #define NUMARG6(...) _NARG6(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define _NARG7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7 #define NUMARG7(...) _NARG7(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) #define _NARG8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8 #define NUMARG8(...) _NARG8(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define _NARG9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 #define NUMARG9(...) _NARG9(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define __VARIADIC(name, num_args, ...) name ## _ ## num_args (__VA_ARGS__) #define _VARIADIC(name, num_args, ...) name (__VARIADIC(name, num_args, __VA_ARGS__)) #define VARIADIC(name, num_args, ...) _VARIADIC(name, num_args, __VA_ARGS__) #define VARIADIC2(name, num_args, ...) __VARIADIC(name, num_args, __VA_ARGS__) // Vary function name by number of arguments supplied #define VARIADIC_NAME(name, num_args) name ## _ ## num_args ## _name () #define NVARIADIC(name, num_args, ...) _VARIADIC(VARIADIC_NAME(name, num_args), num_args, __VA_ARGS__) #endif

Escenario de uso simplificado:

const uint32* uint32_frombytes(uint32* out, const uint8* in, size_t bytes); /* The output buffer defaults to NULL if not provided. */ #include "variadic.h" #define uint32_frombytes_2( b, c) NULL, b, c #define uint32_frombytes_3(a, b, c) a, b, c #define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

Y con _Generic:

const uint8* uint16_tobytes(const uint16* in, uint8* out, size_t bytes); const uint16* uint16_frombytes(uint16* out, const uint8* in, size_t bytes); const uint8* uint32_tobytes(const uint32* in, uint8* out, size_t bytes); const uint32* uint32_frombytes(uint32* out, const uint8* in, size_t bytes); /* The output buffer defaults to NULL if not provided. Generic function name supported on the non-uint8 type, except where said type is unavailable because the argument for output buffer was not provided. */ #include "variadic.h" #define uint16_tobytes_2(a, c) a, NULL, c #define uint16_tobytes_3(a, b, c) a, b, c #define uint16_tobytes(...) VARIADIC( uint16_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__) #define uint16_frombytes_2( b, c) NULL, b, c #define uint16_frombytes_3(a, b, c) a, b, c #define uint16_frombytes(...) VARIADIC(uint16_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__) #define uint32_tobytes_2(a, c) a, NULL, c #define uint32_tobytes_3(a, b, c) a, b, c #define uint32_tobytes(...) VARIADIC( uint32_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__) #define uint32_frombytes_2( b, c) NULL, b, c #define uint32_frombytes_3(a, b, c) a, b, c #define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__) #define tobytes(a, ...) _Generic((a), / const uint16*: uint16_tobytes, / const uint32*: uint32_tobytes) (VARIADIC2( uint32_tobytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__)) #define frombytes(a, ...) _Generic((a), / uint16*: uint16_frombytes, / uint32*: uint32_frombytes)(VARIADIC2(uint32_frombytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

Y con la selección de nombre de función variable, que no se puede combinar con _Generic:

// winternitz() with 5 arguments is replaced with merkle_lamport() on those 5 arguments. #define merkle_lamport_5(a, b, c, d, e) a, b, c, d, e #define winternitz_7(a, b, c, d, e, f, g) a, b, c, d, e, f, g #define winternitz_5_name() merkle_lamport #define winternitz_7_name() winternitz #define winternitz(...) NVARIADIC(winternitz, NUMARG7(__VA_ARGS__), __VA_ARGS__)


No, esa es una característica del lenguaje C ++.


No, pero podría considerar usar un conjunto de funciones (o macros) para aproximarse usando argumentos predeterminados:

// No default args int foo3(int a, int b, int c) { return ...; } // Default 3rd arg int foo2(int a, int b) { return foo3(a, b, 0); // default c } // Default 2nd and 3rd args int foo1(int a) { return foo3(a, 1, 0); // default b and c }


No.


No.

Ni siquiera el último estándar C99 lo admite.


Otra opción más usa struct s:

struct func_opts { int arg1; char * arg2; int arg3; }; void func(int arg, struct func_opts *opts) { int arg1 = 0, arg3 = 0; char *arg2 = "Default"; if(opts) { if(opts->arg1) arg1 = opts->arg1; if(opts->arg2) arg2 = opts->arg2; if(opts->arg3) arg3 = opts->arg3; } // do stuff } // call with defaults func(3, NULL); // also call with defaults struct func_opts opts = {0}; func(3, &opts); // set some arguments opts.arg3 = 3; opts.arg2 = "Yes"; func(3, &opts);


Otro truco usando macros:

#include <stdio.h> #define func(...) FUNC(__VA_ARGS__, 15, 0) #define FUNC(a, b, ...) func(a, b) int (func)(int a, int b) { return a + b; } int main(void) { printf("%d/n", func(1)); printf("%d/n", func(1, 2)); return 0; }

Si solo se pasa un argumento, b recibe el valor predeterminado (en este caso 15)


Podemos crear funciones que usan parámetros con nombre (solo) para los valores predeterminados. Esta es una continuación de la respuesta de bk.

#include <stdio.h> struct range { int from; int to; int step; }; #define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__}) /* use parentheses to avoid macro subst */ void (range)(struct range r) { for (int i = r.from; i <= r.to; i += r.step) printf("%d ", i); puts(""); } int main() { range(); range(.from=2, .to=4); range(.step=2); }

El estándar C99 define que los nombres posteriores en la inicialización anulan los elementos anteriores. También podemos tener algunos parámetros posicionales estándar, solo cambia la macro y la firma de la función en consecuencia. Los parámetros de valor predeterminado solo se pueden usar en el estilo de parámetro nombrado.

Salida del programa:

1 2 3 4 5 6 7 8 9 10 2 3 4 1 3 5 7 9


Probablemente la mejor manera de hacer esto (lo que puede o no ser posible en su caso dependiendo de su situación) es pasar a C ++ y usarlo como ''una mejor C''. Puede usar C ++ sin usar clases, plantillas, sobrecarga de operadores u otras características avanzadas.

Esto le dará una variante de C con sobrecarga de funciones y parámetros predeterminados (y cualquier otra característica que elija usar). Solo tienes que ser un poco disciplinado si realmente quieres usar solo un subconjunto restringido de C ++.

Mucha gente dirá que es una idea terrible usar C ++ de esta manera, y pueden tener un punto. Pero es solo una opinión; Creo que es válido usar las características de C ++ con las que te sientas cómodo sin tener que comprar todo. Creo que una parte importante de la razón del éxito de C ++ es que se usó por una gran cantidad de programadores en sus primeros días exactamente de esta manera.


Realmente no. La única forma sería escribir una función de varargs y completar manualmente los valores predeterminados para los argumentos que la persona que llama no pasa.


A través de macros

3 parámetros:

#define my_func2(...) my_func3(__VA_ARGS__, 0.5) #define my_func1(...) my_func2(__VA_ARGS__, 10) #define VAR_FUNC(_1, _2, _3, NAME, ...) NAME #define my_func(...) VAR_FUNC(__VA_ARGS__, my_func3, my_func2, my_func1)(__VA_ARGS__) void my_func3(char a, int b, float c) // b=10, c=0.5 { printf("a=%c; b=%d; c=%f/n", a, b, c); }

Si desea un cuarto argumento, entonces debe agregar un my_func3 adicional. Observe los cambios en VAR_FUNC, my_func2 y my_func

4 parámetros:

#define my_func3(...) my_func4(__VA_ARGS__, "default") // <== New function added #define my_func2(...) my_func3(__VA_ARGS__, (float)1/2) #define my_func1(...) my_func2(__VA_ARGS__, 10) #define VAR_FUNC(_1, _2, _3, _4, NAME, ...) NAME #define my_func(...) VAR_FUNC(__VA_ARGS__, my_func4, my_func3, my_func2, my_func1)(__VA_ARGS__) void my_func4(char a, int b, float c, const char* d) // b=10, c=0.5, d="default" { printf("a=%c; b=%d; c=%f; d=%s/n", a, b, c, d); }

La única excepción a la que a las variables flotantes no se les pueden dar valores predeterminados (a menos que sea el último argumento como en el caso de los 3 parámetros ), porque necesitan el período (''.''), Que no se acepta dentro de los argumentos de macro. Pero puede encontrar una solución alternativa como se ve en la macro my_func2 (en el caso de 4 parámetros )

Programa

int main(void) { my_func(''a''); my_func(''b'', 20); my_func(''c'', 200, 10.5); my_func(''d'', 2000, 100.5, "hello"); return 0; }

Salida:

a=a; b=10; c=0.500000; d=default a=b; b=20; c=0.500000; d=default a=c; b=200; c=10.500000; d=default a=d; b=2000; c=100.500000; d=hello


Sí, con las características de C99 puedes hacer esto. Esto funciona sin definir nuevas estructuras de datos o algo así, y sin que la función tenga que decidir en tiempo de ejecución cómo se llamó, y sin ningún costo de cálculo.

Para una explicación detallada vea mi post en

http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/

Jens


Sí, puedes hacer algo parecido, aquí tienes que conocer las diferentes listas de argumentos que puedes obtener, pero tienes la misma función para manejar todo.

typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET; typedef struct{ INPUT_SET type; char* text; } input_set1; typedef struct{ INPUT_SET type; char* text; int var; } input_set2; typedef struct{ INPUT_SET type; int text; } input_set3; typedef union { INPUT_SET type; input_set1 set1; input_set2 set2; input_set3 set3; } MY_INPUT; void my_func(MY_INPUT input) { switch(input.type) { case my_input_set1: break; case my_input_set2: break; case my_input_set3: break; default: // unknown input break; } }


Sí. :-) Pero no de la forma que cabría esperar.

int f1(int arg1, double arg2, char* name, char *opt); int f2(int arg1, double arg2, char* name) { return f1(arg1, arg2, name, "Some option"); }

Desafortunadamente, C no le permite sobrecargar los métodos, por lo que terminaría con dos funciones diferentes. Aún así, al llamar a f2, en realidad estaría llamando a f1 con un valor predeterminado. Esta es una solución "No se repita", que le ayuda a evitar copiar / pegar el código existente.


Wow, todo el mundo es tan pesimista por aquí. La respuesta es sí.

No es trivial: al final, tendremos la función central, una estructura de soporte, una función de envoltorio y una macro alrededor de la función de envoltorio. En mi trabajo tengo un conjunto de macros para automatizar todo esto; Una vez que entiendas el flujo, te será fácil hacer lo mismo.

He escrito esto en otra parte, así que aquí hay un enlace externo detallado para complementar el resumen aquí: http://modelingwithdata.org/arch/00000022.htm

Nos gustaría convertir

double f(int i, double x)

en una función que toma valores predeterminados (i = 8, x = 3.14). Definir una estructura compañera:

typedef struct { int i; double x; } f_args;

Cambie el nombre de su función f_base y defina una función de contenedor que establezca valores predeterminados y llame a la base:

double var_f(f_args in){ int i_out = in.i ? in.i : 8; double x_out = in.x ? in.x : 3.14; return f_base(i_out, x_out); }

Ahora agregue una macro, usando las macros variadic de C. De esta manera, los usuarios no tienen que saber que en realidad están f_args una estructura de f_args y piensan que están haciendo lo habitual:

#define f(...) var_f((f_args){__VA_ARGS__});

OK, ahora todo lo siguiente funcionaría:

f(3, 8); //i=3, x=8 f(.i=1, 2.3); //i=1, x=2.3 f(2); //i=2, x=3.14 f(.x=9.2); //i=8, x=9.2

Verifique las reglas sobre cómo los inicializadores compuestos establecen valores predeterminados para las reglas exactas.

Una cosa que no funcionará: f(0) , porque no podemos distinguir entre un valor faltante y cero. En mi experiencia, esto es algo a tener en cuenta, pero puede solucionarse a medida que surja la necesidad: la mitad de las veces el valor predeterminado es cero.

Pasé por el problema de escribir esto porque creo que los argumentos con nombre y los valores predeterminados realmente hacen que la codificación en C sea más fácil y aún más divertida. Y C es increíble por ser tan simple y tener suficiente para hacer todo esto posible.


OpenCV usa algo como:

/* in the header file */ #ifdef __cplusplus /* in case the compiler is a C++ compiler */ #define DEFAULT_VALUE(value) = value #else /* otherwise, C compiler, do nothing */ #define DEFAULT_VALUE(value) #endif void window_set_size(unsigned int width DEFAULT_VALUE(640), unsigned int height DEFAULT_VALUE(400));

Si el usuario no sabe lo que debe escribir, este truco puede ser útil:


Respuesta corta: No.

Respuesta ligeramente más larga: hay una solución antigua y antigua en la que pasa una cadena que analiza para argumentos opcionales:

int f(int arg1, double arg2, char* name, char *opt);

donde opt puede incluir un par de "nombre = valor" o algo, y que llamarías como

n = f(2,3.0,"foo","plot=yes save=no");

Obviamente esto solo es ocasionalmente útil. Generalmente cuando se desea una única interfaz para una familia de funcionalidades.

Aún se encuentra este enfoque en los códigos de física de partículas que están escritos por programas profesionales en c ++ (como por ejemplo ROOT ). Su principal ventaja es que puede extenderse casi indefinidamente mientras se mantiene la compatibilidad.