Default values in a C Struct

前端 未结 10 1583
闹比i
闹比i 2020-11-29 16:59

I have a data structure like this:

    struct foo {
        int id;
        int route;
        int backup_route;
        int current_route;
    }

and a

相关标签:
10条回答
  • 2020-11-29 17:17

    You can change your secret special value to 0, and exploit C's default structure-member semantics

    struct foo bar = { .id = 42, .current_route = new_route };
    update(&bar);
    

    will then pass 0 as members of bar unspecified in the initializer.

    Or you can create a macro that will do the default initialization for you:

    #define FOO_INIT(...) { .id = -1, .current_route = -1, .quux = -1, ## __VA_ARGS__ }
    
    struct foo bar = FOO_INIT( .id = 42, .current_route = new_route );
    update(&bar);
    
    0 讨论(0)
  • 2020-11-29 17:23

    How about something like:

    struct foo bar;
    update(init_id(42, init_dont_care(&bar)));
    

    with:

    struct foo* init_dont_care(struct foo* bar) {
      bar->id = dont_care;
      bar->route = dont_care;
      bar->backup_route = dont_care;
      bar->current_route = dont_care;
      return bar;
    }
    

    and:

    struct foo* init_id(int id, struct foo* bar) {
      bar->id = id;
      return bar;
    }
    

    and correspondingly:

    struct foo* init_route(int route, struct foo* bar);
    struct foo* init_backup_route(int backup_route, struct foo* bar);
    struct foo* init_current_route(int current_route, struct foo* bar);
    

    In C++, a similar pattern has a name which I don't remember just now.

    EDIT: It's called the Named Parameter Idiom.

    0 讨论(0)
  • 2020-11-29 17:27

    I'm rusty with structs, so I'm probably missing a few keywords here. But why not start with a global structure with the defaults initialized, copy it to your local variable, then modify it?

    An initializer like:

    void init_struct( structType * s )
    {
       memcopy(s,&defaultValues,sizeof(structType));
    }
    

    Then when you want to use it:

    structType foo;
    init_struct( &foo ); // get defaults
    foo.fieldICareAbout = 1; // modify fields
    update( &foo ); // pass to function
    
    0 讨论(0)
  • 2020-11-29 17:28

    Since it looks like that you only need this structure for the update() function, don't use a structure for this at all, it will only obfuscate your intention behind that construct. You should maybe rethink why you are changing and updating those fields and define separate functions or macros for this "little" changes.

    e.g.

    
    #define set_current_route(id, route) update(id, dont_care, dont_care, route)
    #define set_route(id, route) update(id, dont_care, route, dont_care)
    #define set_backup_route(id, route) update(id, route, dont_care, dont_care)
    

    Or even better write a function for every change case. As you already noticed you don't change every property at the same time, so make it possible to change only one property at a time. This doesn't only improve the readability, but also helps you handling the different cases, e.g. you don't have to check for all the "dont_care" because you know that only the current route is changed.

    0 讨论(0)
  • 2020-11-29 17:32

    Perhaps consider using a preprocessor macro definition instead:

    #define UPDATE_ID(instance, id)  ({ (instance)->id= (id); })
    #define UPDATE_ROUTE(instance, route)  ({ (instance)->route = (route); })
    #define UPDATE_BACKUP_ROUTE(instance, route)  ({ (instance)->backup_route = (route); })
    #define UPDATE_CURRENT_ROUTE(instance, route)  ({ (instance)->current_route = (route); })
    

    If your instance of (struct foo) is global, then you don't need the parameter for that of course. But I'm assuming you probably have more than one instance. Using the ({ ... }) block is a GNU-ism that that applies to GCC; it is a nice (safe) way to keep lines together as a block. If you later need to add more to the macros, such as range validation checking, you won't have to worry about breaking things like if/else statements and so forth.

    This is what I would do, based upon the requirements you indicated. Situations like this are one of the reasons that I started using python a lot; handling default parameters and such becomes a lot simpler than it ever is with C. (I guess that's a python plug, sorry ;-)

    0 讨论(0)
  • 2020-11-29 17:37

    <stdarg.h> allows you to define variadic functions (which accept an indefinite number of arguments, like printf()). I would define a function which took an arbitrary number of pairs of arguments, one which specifies the property to be updated, and one which specifies the value. Use an enum or a string to specify the name of the property.

    0 讨论(0)
提交回复
热议问题