I'm using GCC 4.6.2 (Mingw) and compiling with -Wextra. I'm getting strange warnings whenever I use designated initializers. For the following code
typedef struct
{
int x;
int y;
} struct1;
typedef struct
{
int x;
int y;
} struct2;
typedef struct
{
struct1 s1;
struct2 s2[4];
} bug_struct;
bug_struct bug_struct1 =
{
.s1.x = 1,
.s1.y = 2,
.s2[0].x = 1,
.s2[0].y = 2,
.s2[1].x = 1,
.s2[1].y = 2,
.s2[2].x = 1,
.s2[2].y = 2,
.s2[3].x = 1,
.s2[3].y = 2,
};
I get warnings
bug.c:24:3: warning: missing initializer [-Wmissing-field-initializers]
bug.c:24:3: warning: (near initialization for 'bug_struct1.s1.y') [-Wmissing-field-initializers]
So what exactly is missing? I've initialized every member. Is this warning merely too blunt to work with designated initializers, am I doing something wrong, or is it a compiler bug?
It seems that the warning is, as you say, "too blunt".
This pattern of access, initializing each member struct as a whole, satisfies the compiler:
bug_struct bug_struct1 =
{
.s1 = {.x = 1, .y = 2},
.s2[0] = {.x = 1, .y = 2},
.s2[1] = {.x = 1, .y = 2},
.s2[2] = {.x = 1, .y = 2},
.s2[3] = {.x = 1, .y = 2}
};
Related
I have to initialize an structure using a point to it, in a way that upper_left is the point (10,25) and lower_right(20,15)
struct point {int x, y;};
struct rectangle {struct point upper_left, lower_right;};
struct rectangle *p;
p = malloc(sizeof(*p));
p->upper_left.x = 10;
p->upper_left.y = 25;
p->lower_right.x = 20;
p->lower_right.y = 15;
Is there any way to do it more "compact" and not one by one? I've tried this but the errors from the compiler are the same "Expected expression before '{' token"
p->upper_left = {10, 25};
p->lower_right = {20,15};
/////////////
p->upper_left = {.x = 10, .y = 25};
p->lower_right = {.x = 20, .y = 15};
//////////////////////////////
*p = {.upper_left = {10, 25}, .lower_right = {20, 15}};
Yes compound literal
p->upper_left = (struct point){10, 25};
*p = (struct rectangle){.upper_left = {10, 25}, .lower_right = {20, 15}};
you can experiment yourself here: https://godbolt.org/z/yw_JC0
I have a struct defined with typedef
typedef struct
{
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t height;
}TArea;
Now I want to create some areas that depends on each other.
Something like
AreaDefs.h
extern TArea UI_AREA_1;
extern TArea UI_AREA_2;
AreaDefs.c
TArea UI_AREA_1 = {.x = 0, .y = 0, .width = 5, .height = 10};
TArea UI_AREA_2 = {.x = UI_AREA_1.x, .y = 200, .width = 5, .height = 10};
Why do i get "Error: expression must have a constant value" and whats a better solution? I dotn want to make something like
#define X_VAL 0
TArea UI_AREA_1 = {.x = X_VAL, .y = 0, .width = 5, .height = 10};
TArea UI_AREA_2 = {.x = X_VAL, .y = 200, .width = 5, .height = 10};
because of in my real application I have more than this two areas that depends on each other.
When initializing a variable, the initializer cannot be the value of another variable, even if that variable is defined const. It must be a constant value.
The best you can do is what your second example does: use a #define to initialize certain variables to the same value.
The following code gives me a GCC error for missing braces, but no matter which combinations I try (including just a single value of 0), it does not resolve. Can anyone give some insight?
#define NUM_TABLE_ELEMENTS 1
typedef struct parameter_t
{
struct
{
uint8_t A : 1;
uint8_t B : 1;
uint8_t C : 1;
uint8_t D : 5;
} W;
uint8_t X;
uint8_t Y;
uint8_t Z;
} parameter_t;
parameter_t MyTable[NUM_TABLE_ELEMENTS] =
{
{ { 1, 1, 1, 0 }, 0, 0, 0 },
};
This is why you don't shortcut the question with things you make assumptions on:
The ACTUAL struct I was using was:
typedef struct parameter_t
{
struct
{
uint8_t A : 1;
uint8_t B : 1;
uint8_t C : 1;
uint8_t D : 5;
} W;
uint8_t X;
uint8_t Y[1];
uint8_t Z[1];
} parameter_t;
parameter_t MyTable[NUM_TABLE_ELEMENTS] =
{
{ { 1, 1, 1, 0 }, 0, 0, 0 },
};
So it was missing braces around the other arrays, even though they were single element... Feel free to downvote me for my slacking.
Is there any way to do this in a condensed form?
GLfloat coordinates[8];
...
coordinates[0] = 1.0f;
coordinates[1] = 0.0f;
coordinates[2] = 1.0f;
coordinates[3] = 1.0f;
coordinates[4] = 0.0f;
coordinates[5] = 1.0f;
coordinates[6] = 0.0f;
coordinates[7] = 0.0f;
return coordinates;
Something like coordinates = {1.0f, ...};?
If you really to assign values (as opposed to initialize), you can do it like this:
GLfloat coordinates[8];
static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
...
memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));
return coordinates;
Although in your case, just plain initialization will do, there's a trick to wrap the array into a struct (which can be initialized after declaration).
For example:
struct foo {
GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };
The old-school way:
GLfloat coordinates[8];
...
GLfloat *p = coordinates;
*p++ = 1.0f; *p++ = 0.0f; *p++ = 1.0f; *p++ = 1.0f;
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; *p++ = 0.0f;
return coordinates;
You can use:
GLfloat coordinates[8] = {1.0f, ..., 0.0f};
but this is a compile-time initialisation - you can't use that method in the current standard to re-initialise (although I think there are ways to do it in the upcoming standard, which may not immediately help you).
The other two ways that spring to mind are to blat the contents if they're fixed:
GLfloat base_coordinates[8] = {1.0f, ..., 0.0f};
GLfloat coordinates[8];
:
memcpy (coordinates, base_coordinates, sizeof (coordinates));
or provide a function that looks like your initialisation code anyway:
void setCoords (float *p0, float p1, ..., float p8) {
p0[0] = p1; p0[1] = p2; p0[2] = p3; p0[3] = p4;
p0[4] = p5; p0[5] = p6; p0[6] = p7; p0[7] = p8;
}
:
setCoords (coordinates, 1.0f, ..., 0.0f);
keeping in mind those ellipses (...) are placeholders, not things to literally insert in the code.
I went with an array initialization method:
#include <stdarg.h>
void int_array_init(int *a, const int ct, ...) {
va_list args;
va_start(args, ct);
for(int i = 0; i < ct; ++i) {
a[i] = va_arg(args, int);
}
va_end(args);
}
called like,
const int node_ct = 8;
int expected[node_ct];
int_array_init(expected, node_ct, 1, 3, 4, 2, 5, 6, 7, 8);
The C99 array initialization, like this:
const int node_ct = 8;
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
And in the configure.ac:
AC_PROG_CC_C99
had the compiler on my dev box perfectly happy. The compiler on the server complained with:
error: variable-sized object may not be initialized
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
and
warning: excess elements in array initializer
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
for each element
It doesn't complain at all about, for example:
int expected[] = { 1, 2, 3, 4, 5 };
I like the check on size, and that the varargs support is acting more robustly than the support for the array initializer.
Find PR with sample code at https://github.com/wbreeze/davenport/pull/15/files
Regarding https://stackoverflow.com/a/3535455/608359 from #paxdiablo, I liked it; but, felt insecure about having the number of times the initializaion pointer advances synchronized with the number of elements allocated to the array. Worst case, the initializing pointer moves beyond the allocated length. As such, the diff in the PR contains,
int expected[node_ct];
- int *p = expected;
- *p++ = 1; *p++ = 2; *p++ = 3; *p++ = 4;
+ int_array_init(expected, node_ct, 1, 2, 3, 4);
The int_array_init method will safely assign junk if the number of
arguments is fewer than the node_ct. The junk assignment ought to be easier
to catch and debug.
Exactly, you nearly got it:
GLfloat coordinates[8] = {1.0f, ..., 0.0f};
If you are doing these same assignments a lot in your program and want a shortcut, the most straightforward solution might be to just add a function
static inline void set_coordinates(
GLfloat coordinates[static 8],
GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3,
GLfloat c4, GLfloat c5, GLfloat c6, GLfloat c7)
{
coordinates[0] = c0;
coordinates[1] = c1;
coordinates[2] = c2;
coordinates[3] = c3;
coordinates[4] = c4;
coordinates[5] = c5;
coordinates[6] = c6;
coordinates[7] = c7;
}
and then simply call
GLfloat coordinates[8];
// ...
set_coordinates(coordinates, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
typedef struct{
char array[4];
}my_array;
my_array array = { .array = {1,1,1,1} }; // initialisation
void assign(my_array a)
{
array.array[0] = a.array[0];
array.array[1] = a.array[1];
array.array[2] = a.array[2];
array.array[3] = a.array[3];
}
char num = 5;
char ber = 6;
int main(void)
{
printf("%d\n", array.array[0]);
// ...
// this works even after initialisation
assign((my_array){ .array = {num,ber,num,ber} });
printf("%d\n", array.array[0]);
// ....
return 0;
}
How can I initialize this nested struct in C?
typedef struct _s0 {
int size;
double * elems;
}StructInner ;
typedef struct _s1 {
StructInner a, b, c, d, e;
long f;
char[16] s;
}StructOuter; StructOuter myvar = {/* what ? */ };
To initialize everything to 0 (of the right kind)
StructOuter myvar = {0};
To initialize the members to a specific value
StructOuter myvar = {{0, NULL}, {0, NULL}, {0, NULL},
{0, NULL}, {0, NULL}, 42.0, "foo"};
/* that's {a, b, c, d, e, f, s} */
/* where each of a, b, c, d, e is {size, elems} */
Edit
If you have a C99 compiler, you can also use "designated initializers", as in:
StructOuter myvar = {.c = {1000, NULL}, .f = 42.0, .s = "foo"};
/* c, f, and s initialized to specific values */
/* a, b, d, and e will be initialized to 0 (of the right kind) */
To highlight struct labels in particular:
StructInner a = {
.size: 1,
.elems: { 1.0, 2.0 }, /* optional comma */
};
StructOuter b = {
.a = a, /* struct labels start with a dot */
.b = a,
a, /* they are optional and you can mix-and-match */
a,
.e = { /* nested struct initialization */
.size: 1,
.elems: a.elems
},
.f = 1.0,
.s = "Hello", /* optional comma */
};
double a[] = { 1.0, 2.0 };
double b[] = { 1.0, 2.0, 3.0 };
StructOuter myvar = { { 2, a }, { 3, b }, { 2, a }, { 3, b }, { 2, a }, 1, "a" };
It seems a and b cannot be initialized in-place in plain C
Following also works with GCC, C99. GCC doesnt complain about it. I am not sure if this is standard.
double arr[] = { 1.0, 2.0 }; // should be static or global
StructOuter myvar =
{
.f = 42,
.s = "foo",
.a.size = 2,
.a.elems = &arr,
.b.size = 0, // you can explicitly show that it is zero
// missing members will actually be initialized to zero
};