I'm trying to implement a flexible debug macro/function lib and named/optional arguments seem like the best way to implement the functions.
Is there a nicer way to do named arguments in c then the following?
enum named_args {NAME,ADRESS,AGE,NA_SENTINEL};
void named_arg_initializers(struct person p, enum * named_args)
{
enum named_args * current_name;
enum named_args * current_arg;
...
if(named_args==NULL)
return;
current_name = named_args[0];
current_arg = named_args[1];
while(current_name!=NA_SENTINEL)
{
current_name+=2;
current_arg+=2;
if(current_name==NAME)
p.name=current_arg;
else if(...
...
}
...
}
...
}
The main advantage of named arguments in C# is that we can pass the arguments out of their positional order. Simply put, we don't have to remember the order of parameters. They also increase the readability of the application, especially in cases where all the arguments are of the same type.
When you mix named and unnamed arguments in a function call, the unnamed arguments must come before the named ones in the argument list. Thus, when writing a function, you should put required arguments to the function in the argument list before the ones that you consider optional.
Yes, it matters. The arguments must be given in the order the function expects them. C passes arguments by value. It has no way of associating a value with an argument other than by position.
The caller's arguments passed to the function's parameters do not have to have the same names.
Sure.
struct toto {
unsigned age;
char name[25];
};
void func(struct toto);
...
func((struct toto){ .name = "you", .age = 18 });
or if you want you may wrap that in a macro
#define FUNC(...) func((struct toto){ __VA_ARGS__ })
...
FUNC(.name = "you", .age = 18 );
The way you've shown isn't valid unless the named arguments are all compatible with enum
(you could fix that by using a void *
argument).
However, you could do something similar with varargs which looks neater:
#include <stdarg.h>
enum named_args { NAME, ADDRESS, AGE, NA_SENTINEL };
void named_arg_initializers(struct person *p, ...)
{
va_list ap;
enum named_args argn;
va_start(ap, p);
for (argn = va_arg(ap, enum named_args); argn != NA_SENTINEL; argn = va_arg(ap, enum named_args))
{
switch (argn)
{
case NAME:
p->name = va_arg(ap, char *);
break;
case AGE:
p->age = va_arg(ap, int);
break;
/* ... */
}
}
va_end(ap);
/* ... */
}
You'd use it like so:
named_arg_initializers(&p, AGE, 110, NAME, "Claude Choules", NA_SENTINEL);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With