1

Consider the following struct and function to create the struct:

#define MAX_ELEMS 1000

struct stuff {
  double magic;
  bool is_valid[MAX_ELEMS];
  double values[MAX_ELEMS];
};

struct stuff make_stuff(double magic) {
    return (struct stuff){
        .magic = magic
    };
}

In my case, I need stuff.magic to be intialized to the given value, and the stuff.is_valid array to be zero initialized, but I do not want to initialize stuff.values (as they are guarded by stuff.is_valid and initialized on-demand later).

Can I achieve this with designated initalizers?

I know I can achieve it without, but this is uglier and more error-prone (among other reasons, as I now need to explicitly zero stuff.is_valid, perhaps with a memset).

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386

2 Answers2

4

Any field not specifically initialized will be filled with zeros.

So, no, if you initialize any fields, they all get something (even if its just zeros)

abelenky
  • 63,815
  • 23
  • 109
  • 159
1

It can only be done by "normal" assignments and memset.

struct stuff make_stuff(double magic) 
{  
    struct stuff s;
    memset(s.is_valid, 0, sizeof(s.is_valid));
    s.magic = magic;
    return s;
} 

But if you are looking for the efficiency returning such a large struct makes no sense as it will me twice copied in full as structs are passed by the value

It is better to pass the pointer to the structure.

struct stuff *make_stuff(struct stuff *s, double magic) 
{  
    memset(s -> is_valid, 0, sizeof(s -> is_valid));
    s -> magic = magic;
    return s;
} 
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    Return by value is fine as long as `make_stuff` can inline. Then it's a good way to write a wrapper you can use for `struct stuff foo = make_stuff(1.0);`. – Peter Cordes Jul 27 '20 at 21:31
  • 1
    @PeterCordes - inlining isn't always necessary, at least with a reasonable ABI. The caller will pass a pointer to the area for the return value, and the caller will fill in the return value directly and no copy needs to be made in the caller. This "optimization" happens even at `-O0` for [clang and gcc](https://godbolt.org/z/x6hEzs). Admittedly it doesn't work in all scenarios as [caller2](https://godbolt.org/z/vYbjE3) illustrates (I believe this works in C++ though, which has additional language that makes it possible). – BeeOnRope Jul 27 '20 at 22:09
  • @BeeOnRope: Hmm, also inlining isn't always sufficient. https://godbolt.org/z/5h1cE4 shows that with an arg of `1.0` instead of `0.`, gcc misses an optimization and does still a 9008 byte memcpy, while clang doesn't. So taking an output arg explicitly, instead of implicitly via the calling convention, is apparently safer. – Peter Cordes Jul 27 '20 at 22:29
  • @PeterCordes - that's certainly weird. In any case, my usages are of the form `struct stuff s = make(...)`, i.e., assignment to a newly defined object, which seems to be less problematic. – BeeOnRope Jul 27 '20 at 23:50
  • @PeterCordes triviality of the example makes inlining possible. – 0___________ Jul 28 '20 at 08:18
  • @P__J__: Yup, unless you put it in another file and fail to use link-time optimization. I might have declared them `inline` to make it more obvious you should put these in headers, unless LTO is very widely used these days. (It should be but probably isn't as widespread as we'd hope, given that options to enable it are less portable than `-O2`.) – Peter Cordes Jul 28 '20 at 09:32
  • @PeterCordes `inline` does not matters too much this days. To force inlining you need to use compiler extensions like gcc `__attribute__(())`. It is a new trend: `In LTO we trust` but I would be more sceptic. I would like to see disassembly of the more complex code with structs returned by value linked using LTO. – 0___________ Jul 28 '20 at 09:43
  • @P__J__: `inline` on the declaration in an SO answer serves as a hint to readers to put this in a `.h`, and/or that you should somehow arrange for this to get inlined. Agreed that it shouldn't actually matter if you use LTO, but some projects get compiled without (at least sometimes). – Peter Cordes Jul 28 '20 at 09:52
  • @PeterCordes: If LTO had been expected when C had been standardized, it would have included ways by which programs could specify the semantics that used to be implied by calls across compilation unit boundaries. Even if only 1% of function calls would need such semantics, "optimizing away" such semantics from the functions that require them is a recipe for Heisenbugs. – supercat Aug 03 '20 at 03:44