2

I'm trying to initialize a struct which has a union inside and am not sure how to do it correctly. The code is part of a bigger GitHub Repository, so I don't want to change the initial code. Here's the Struct :

typedef struct SYP_encoder_stru {
char name[15];      
u8 type;            
s16 val_min;        
s16 val_max;        
s16 value;          
u8 step;            
u8 miditype;        

union {
    u8 midicc;          
    u16 midirpn;        
    u16 midinrpn;       
};
u8 mapping;         
u16 wordstart;      
u16 ebpos;          
} SYP_encoder_struct;

If I want to create an Encoder Struct in another file, would this be right?:

SYP_encoder_struct enc1 = {
"OSC1 Shape", //name
0,            //type
0,            //val min
127,          //val max
0,            //value
1,            //stepping
0,            //miditype
20,           //midicc?? what about midirpn and midinrpn
0,            //mapping
0,            //wordstart      
0             //ebpos
};

I'm just not sure because of the Union. Is this how to initiliaze a struct if it has an union inside? What if I want to initiliaze midirpn or midinrpn instead of midicc?

P.S.: The Code is written in C, sorry forgot to mention.

3
  • 6
    what langauge is it? C and C++ are two different languages, please only tag the one that applies Commented Aug 3, 2022 at 13:50
  • 3
    And AFAIK, the rules for C and C++ are different w.r,t initialization — C has designated initializers which solve most of the problems, but C++ does not. Even in C, you can only initialize one of the members of a union, but you can choose which one. Specify .midirpn = 37 or whatever. Commented Aug 3, 2022 at 13:59
  • Sorry forgot to mention, it is written in C Commented Aug 3, 2022 at 14:05

2 Answers 2

2

The correct way to initialize a struct like this depends on the newest version of C that your compiler can handle.

The example you gave is perfectly valid, and is called a designated initializer.

If your compiler can handle C99 or newer, then you can use compound literals like this:

SYP_encoder_struct enc1 = (SYP_encoder_struct){
.name = "OSC1 Shape", .type = 0, .val_min = 0, .val_max = 127, .value = 0,
.stepping = 1, .miditype = 0, .midicc = 20, .mapping = 0, .wordstart = 0,
.ebpos = 0 };

Alternatively, you can individually assign to each element in the struct:

SYP_encoder_struct enc1;
strcpy(enc1.name,"OSC1 Shape",strlen("OSC1 Shape"));
enc1.type = 0;
enc1.val_min = 0;
enc1.val_max = 127;
enc1.value = 0;
enc1.stepping = 1;
enc1.miditype = 0;
enc1.midicc = 20;
enc1.mapping = 0;
enc1.wordstart = 0;      
enc1.ebpos = 0;

As to the union aspect of the struct, the members .midicc, .midirpn, and .midinrpn are members of an anonymous union, which means they can each be accessed directly i.e. enc1.midicc, enc1.midirpn, enc1.midinrpn, but since they are members of a union inside the struct, they reside in overlapping memory, so it doesn't make sense to initialize more than one of them at a time.

If you want to initialize .midirpn or .midinrpn instead of .midicc you can, but those three union members live on-top-of-each-other, so to speak, so only one can be used at a time.

Sign up to request clarification or add additional context in comments.

8 Comments

You don't need to use a compound literal; you could drop the cast notation and the { … } part is a valid designated initializer.
Compound literals were added in C11, not C99 (and they are not needed here). Designated initializers were added in C99.
@Ian Abbot that is incorrect. See ISO/IEC 9899:1999 6.5.2.5
@WillisHershey Yes, sorry. A brainfart on my part. Designated initializers and compound literals were both from C99.
|
1

The union in the struct should given a variable name, such as "union_v":

typedef struct SYP_encoder_stru {
  char name[15];
  u8 type;
  s16 val_min;
  s16 val_max;
  s16 value;
  u8 step;
  u8 miditype;

  union {
    u8 midicc;
    u16 midirpn;
    u16 midinrpn;
  } union_v;
  
  u8 mapping;
  u16 wordstart;
  u16 ebpos;
} SYP_encoder_struct;

And you should set the member using the designated initializer format ".member = value" one by one, and set the union variable directly such as ".union_v.midicc = 20" for midicc, or ".union_v.midirpn" for midirpn.

SYP_encoder_struct enc1 = {
      .name = "OSC1 Shape",  // name
      .type = 0,             // type
      .val_min = 0,          // val min
      .val_max = 127,        // val max
      .value = 0,            // value
      .step = 1,             // stepping
      .miditype = 0,         // miditype
      .union_v.midicc = 20,  // midicc?? what about midirpn and midinrpn
      .mapping = 0,          // mapping
      .wordstart = 0,        // wordstart
      .ebpos = 0             // ebpos
  };

4 Comments

Anonymous unions are perfectly fine from C11 and later
Note that the question correctly uses an anonymous union which means that the OP can drop the .union_v part altogether.
But C language don't support anonymous union
Which C language are you referring to? C11 and C18 both do. Granted, C90 and C99 do not, but they're far from being the current standard. C2x (almost certainly going to be C23) is almost ready — it will support them too, of course.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.