10

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(...
        ...
        }
        ...
    }
    ...
}
Roman A. Taycher
  • 18,619
  • 19
  • 86
  • 141
  • 1
    Well honestly the question is a bit weird... the word "then" at the end makes it look as if it's not really a question (I have no idea what it would be though), and the lack of body text and all just doesn't make it look like a great question. Try fixing the indentation and adding a bit of text in the body to spice it up a bit. (And take out the "then" in the title, since it's a bit awkward.) :) – user541686 May 10 '11 at 09:18
  • Well, what does "nicer" mean? What are your criteria? What is your goal? – Lightness Races in Orbit May 10 '11 at 09:29
  • An older question whose answers address this one (and more) can be found here: https://stackoverflow.com/questions/1472138/c-default-arguments. In particular, see u0b34a0f6ae's answer. – David Mertens Jun 06 '19 at 09:29

3 Answers3

30

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 );
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • That does look sort of nice but it is c99 only. Also does it initialize the other values in the struct to zero? Thats a problem if zero is a valid value. – Roman A. Taycher May 10 '11 at 09:15
  • 5
    @Roman, what do you mean by "C99 only". C99 is the standard for C since 12 years, now. And yes, all initialization in C puts omitted fields to `0`. Just document this as the default value for the fields where `0` is valid :) – Jens Gustedt May 10 '11 at 09:23
  • 1
    Some projects don't like c99 plus doesn't Microsoft compiler not support designated initializers. And the initilization can be important. – Roman A. Taycher May 10 '11 at 09:45
  • 1
    I may sound to critical though, your answer is quite nice(I upvoted it). Especially the fact that unlike mine or most of the ways I can think of its type safe. – Roman A. Taycher May 10 '11 at 09:48
  • I have the impression that most compilers nowadays support many of the C99 features. In particular those used here, designated initializers, compound literals (and vaarg macros) are quite common, I think. – Jens Gustedt May 10 '11 at 10:25
  • 1
    @Jens: The Microsoft C compiler is not and may never be C99 compliant. Also, it appears that the answer is not valid C++ which means that no Microsoft developer can use it which is a significant proportion of all C and C++ programmers. – JeremyP May 10 '11 at 10:47
  • It is completely beyond me how anyone can think designated initializers are more readable. It took me quite a while of staring at the code before I understood what it did, and then this is just a very simple example. The call to the function in the original example is far, far easier to understand. In Java they have the very same syntax option, and as far as I can tell they frown upon to use anonymous objects, as they make the code unreadable. Good code should be easy to _read_ not easy to _write_. – Lundin May 10 '11 at 11:18
  • 1
    @JeremyP, the question is tagged C and not C++. – Jens Gustedt May 10 '11 at 11:29
  • 1
    @Lundin, I wouldn't use neither of these for function interfaces. But otherwise in appropriate places (i.e initialization) designated initializer can really be helpful to make code robust concerning design changes. – Jens Gustedt May 10 '11 at 11:31
  • 1
    @Jens I really don't see how. If you change the struct definition by adding/removing members, you must carefully read through all code using that struct. Designated initializers won't change that. But that's another story... – Lundin May 10 '11 at 11:42
  • 1
    @Lundin, indead, it is another story... removing members may be problematic, yes. Changing order is ok and if you add something, it is initialized to `0` by default. – Jens Gustedt May 10 '11 at 14:03
  • 3
    @Jens: yes I know. The point still stands that this is a C99 only answer and it is therefore legitimate to point that out because people programming C using Microsoft compilers cannot use it. – JeremyP May 10 '11 at 14:13
2

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);
caf
  • 233,326
  • 40
  • 323
  • 462
  • Thank you, thats what I get for not compiling my question, it was late and I was trying to figure out a way to use typed arguments, couldn't, forgot to make arguments void *. – Roman A. Taycher May 11 '11 at 03:22
0

https://github.com/cindRoberta/C/blob/master/structure/function/named_parameter.c

#include<stdio.h>

typedef struct {
  int a;
  float b;
} named_param;

void f_impl(named_param np) {
  printf("%d %g", np.a, np.b);
}

#define f_macro(...) f_impl((named_param){__VA_ARGS__})

int main() {
  f_macro(.a = 4, .b = 9.7);
  //f_impl((named_param){.a = 7, .b = 6.2});

  return 0;
}
Igor Gomes
  • 124
  • 1
  • 4