Cewein
Cewein

Reputation: 444

Initializing typedef arrays in structs

I'm making a Camera struct. the struct use a vec3 which is defined with typedef float vec3[3].

To initialize a vec3 I do vec3 vector = {0.,0.,0.};

My Cameras struct is like this:

typedef struct Cameras {
    vec3 eye;
    vec3 target
} Camera;

but when I do:

Camera cam;
cam.eye = { .5, 1., 0. };

it crashes and the compiler tells me: expression must be modifiable.

I thought it was an error with pointer but no, and replacing vec3 eye to vec3 * eye and cam->eye = {.5,1.,0.} changes nothing.

Am I creating the struct the wrong way or is a really common issue C and I'm just blind?

here my goal is not only to initalise the array, but also accessing the data and modifing/passing into function after the creation.

Upvotes: 1

Views: 823

Answers (3)

Sourav Ghosh
Sourav Ghosh

Reputation: 134416

The error you get is obvious, type of vec3 is float [3] - array type and you certainly cannot "assign" to array types.

You can use the initialization as mentioned by iBug in another answer. However, with a small trick, you'll be able to use the assignment, also. This would need the usage of a pointer and compound literal.

You need to change the typedef to vec3

 typedef float* vec3;

so as to make it a float * and then, you can use compound literal to assign the values, like

cam.eye = (float [3]){ .5, 1., 0. };
cam.target = (float [3]){ .45, 2.5, 0.9 }; // just some other values.

The primary benefit of using this approach is, you are not limited to only "initialization", you can perform the assignment at any time.

P.S. - Compound literals are modifiable, so you do not lose any operation capabilities.

P.P.S.

Quoting C11, chapter §6.5.2.5/ P12

"/tmp/fileXXXXXX" 
 (char []){"/tmp/fileXXXXXX"} 
 (const char []){"/tmp/fileXXXXXX"} 

The first always has static storage duration and has type array of char, but need not be modifiable; the last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.

Upvotes: 1

0___________
0___________

Reputation: 68099

I personally prefer more "descriptive" initialization - I like members to be specified - the code is easier to read for humans.

typedef float vec3[3];

typedef struct Cameras {
    vec3 eye;
    vec3 target;
} Camera;

Camera c = 
{
  .eye = {1.0, 2.0, 3.0},   
  .target = {4.0, 5.0, 6.0},   
};

Camera c1 = 
{
  .target = {4.0, 5.0, 6.0},   
};

Camera c2 = 
{
  .eye = {1.0, 2.0, 3.0},   
};

Upvotes: 0

iBug
iBug

Reputation: 37327

It's because after the line cam is defined, subsequent "assignments" are no longer initializations.

To initialize an instance, you must put the "assignment" at the same place where it's defined:

Camera cam = { {.5, 1., 0.} };

or specifying member:

Camera cam = { .eye = {.5, 1., 0.} };

Note that this will also automatically zero-initialize cam.target as no initial values are specified for it.

Upvotes: 6

Related Questions