Copying an array in a designated initializer - c

I'm trying to initialize a const struct with a designated initializer. However, one of the struct elements is a fixed-width array. I already have the contents I would like to initialize the array with in another fixed-width array of appropriate size.
Is there any way to do this with a designated initializer? A simple (failing example) of what I'm trying to accomplish is demonstrated below.
struct foo {
uint8_t array1[4];
uint8_t array2[4];
}
uint8_t array[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = array, // incompatible pointer to integer conversion
.array2 = { *array } // only copies the first element
};

Short answer: you can't. C does not copy arrays (without the use of (standard library-)functions). The warnings come from the fact that you cannot assign an array as a whole, even when they are static or constant. When an array is used as an r-value in an assignment it decays to a pointer and thus cannot be assigned to another array (as a whole).
The easiest way to go would be to use memcpy, but obviously that must be inside a function.

If bar has global scope, or is declared static, then you won't be able use designated initializers to initialize from non-immediate values, regardless of whether or not the members in question are arrays.
However, if:
bar is declared on the stack of some function, and
Your fixed-size array really does only have 4 elements,
then you might be able to get away with something like this:
#include <stdio.h>
#include <stdint.h>
struct foo {
uint8_t array1[4];
uint8_t array2[4];
};
#define ARRAY_INIT(a) { a[0], a[1], a[2], a[3] }
int main (int argc, char **argv) {
uint8_t arr_init[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = ARRAY_INIT(arr_init),
.array2 = ARRAY_INIT(arr_init),
};
printf("%d, %d\n", bar.array1[0], bar.array2[3]);
return (0);
}
The initializer array must appear before what is being initialized in the stack frame. Or it may come from a function parameter.
Of course if your array is much bigger than this, then using a macro like this will get very messy indeed.

While you may not be able to initialize the array by copying from another array, it may be helpful to use a preprocessor macro:
#define ARRAY_INIT {1, 2, 3, 4}
struct foo const bar = {
.array1 = ARRAY_INIT,
.array2 = ARRAY_INIT
};

Related

Can I access variables using a list of their names dynamically?

I have a list of variables char [][20] ls = {"var_1", "var_2", ... , ""}
which are the names of the fields of a struct struct {char var1[10], ...} my_struct;
The variables inside the struct are all char[] with changing lengths.
The list itself is const and should not change mid-run-time.
I want to access those variables in a loop in a somewhat generic way. Instead of calling myfunc(my_struct.var1); myfunc(my_struct.var2); and so on, I would much rather have:
for (char * p = ls[0]; *p; p += sizeof(ls[0]))
{
myfunc(my_struct.{some magic that would put var_1 / var_2 here});
}
But I guess this is impossible due to fact that the loop is executed in run-time, and the variable name needs to be available in compile-time.
Am I correct or is there something that can be done here? (not have to be this way, just wants to know if I can pack this routine into a nice loop)
Since all members are arrays of the same type, you can create an array of addresses to each member and loop through that:
char *my_struct_addrs[] = { my_struct.var1, my_struct.var2, ... };
int i;
for (i=0; i < sizeof(my_struct_addrs) / sizeof(my_struct_addrs[0]); i++) {
myfunc(my_struct_addrs[i]);
}
Since the size of each of these arrays is different however, you'll need to take care not to pass the bounds of each one. You can address this by keeping track of the size of each field and passing that to the function as well:
struct addr_list {
char *addr;
int len;
};
struct addr_list my_struct_addrs[] = {
{ my_struct.var1, sizeof(my_struct.var1) },
{ my_struct.var2, sizeof(my_struct.var2) },
...
};
int i;
for (i=0; i < sizeof(my_struct_addrs) / sizeof(my_struct_addrs[0]); i++) {
myfunc(my_struct_addrs[i].addr, my_struct_addrs[i].len);
}
Assuming you have something like
const char* ls[] = {"var_1", "var_2", ""};
where this list is not tightly-coupled to the struct data (if so you can use the answer by dbush), but is a separate item for whatever reason.
Then the slightly hacky, but well-defined version would be to use look-up tables. Create two lookup tables, one with strings, one with offsets:
#include <stddef.h>
typedef struct
{
int var_1;
int var_2;
} my_struct_t;
static const char* VAR_STRINGS[] =
{
"var_1",
"var_2",
""
};
static const size_t VAR_OFFSET[] =
{
offsetof(my_struct_t, var_1),
offsetof(my_struct_t, var_2),
};
Then do something like index = search_in_VAR_STRINGS_for(ls[i]); to get an index. (Loop through all items, or use binary search etc). The following code is then actually legal and well-defined:
unsigned char* ptr = (unsigned char*)&my_struct;
ptr += VAR_OFFSET[index];
int var_1 = *(int*)ptr;
This takes padding in account and the pointer arithmetic is guaranteed to be OK by C11 6.3.2.3/7:
When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
And since what's really stored at that address (effective type) is indeed an int, the variable access is guaranteed to be OK by C11 6.5/7 ("strict aliasing"):
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
But various error handling obviously needs to be in place to check that something doesn't go out of bounds.

Initializing structure with variable length array in C

Does anyone know if there is a way to initialize a structure containing a variable length array without initializing the array first in a separate variable (and without using malloc)?
My structure looks like this:
struct my_struct {
int *values;
int size;
}
For now in my code I have that:
void my_function (int size) {
int values[size];
struct my_struct mystr = {
.values = values,
.size = size
};
...
}
(Array is initialized first, then the structure. This is working but it looks awkward to declare a separate variable for the array.)
This would probably work as well:
void my_function (int size) {
struct my_struct mystr = {
.values = calloc (size, sizeof (int)),
.size = size
};
...
}
(but I do not want to use mallocs)
But what I would like to write is something like:
void my_function (int size) {
struct my_struct mystr = {
.values = (int[size]){},
.size = size
};
...
}
Any idea?
First of all, note that you cannot use an array from your stack if you want to return your structure.
int values[size];
struct my_struct mystr = {
.values = values,
.size = size
};
return mystr;
This is not going to work since the lifetime of values ends when you return. The same applies if you try to store mystr in a value pointed by a parameter of your function.
Obviously you're not doing that, however I think it's worth to mention anyway.
Answer to your question: it depends on the situation.
Can you be sure that size is small? Or else your stack is going to overflow in int values[size]. Is it small and predictable? Stick with your first solution. If it can be large or dependent on user-input, definitely use malloc.
Are you in some way returning or retaining a persistent pointer to your structure or values? Use malloc (see my first remark).
Alternatively, you can also use the struct hack but then you would have to malloc the entire mystr anyway.
One more thing, you wrote:
(Array is initialized first, then the structure. This is working but
it looks awkward to declare a separate variable for the array.)
I'm not sure what you mean, but the int * is only sizeof(intptr_t), irregardless of the size of the array. So you're not allocating twice the memory for 1 array, if that's what you're thinking.
Initializer are unnamed objects initialized by the initializer list. Outside the body of a function, the object has static storage duration. So it is possible to use the address of such an object. With a little help from variadic macros you can try →
#include <stdio.h>
struct test {
int count;
int *values;
} test[] = {
#define init(...) { .count=sizeof( (int[]) {__VA_ARGS__} )/sizeof(int), .values=(int *)&(int []){__VA_ARGS__} }
init(0,1,2,3,4),
init(2,4,6,8),
init(1,3),
init(42)
};
#define test_size ((int) (sizeof test/sizeof *test))
int main(void)
{
for(int array=0; array<test_size; ++array) {
printf("array %d (%d) : [ ", array+1, test[array].count);
for(int i=0; i<test[array].count; ++i)
printf("%d ", test[array].values[i]);
puts("]");
}
return 0;
}

How to get total number of elements in an initializer-list at compile-time?

Assume i have define structure which has one array. I have initialize the array in main program. But now how can i find the number of element initialized in the array. I have created arrays of struct object too.
#include <stdio.h>
#define noOfArray 10
struct Arrays
{
int data[100];
int size;
int discardArray; //1 for true and 0 for false
};
void main( )
{
int size=0,i,j;
struct Arrays arrayObject[10]={
{{1,2,3,4}},
{{1,3,5,6,3,4}},
{{1,6,7,8,9,10,11,43,4}}
};
size = sizeof arrayObject[0].data / sizeof arrayObject[0].data[0];
}
This size gives me 100 but i need total number of element present in arrayObject[0].data.
Event tried with
int arr[] = {1,2,3,4};
struct Arrays arrayObject[10] = {
{arr,sizeof arr/sizeof arr[0]},
{{1,3,5,6,3,4}},
{{1,6,7,8,9,10,11,43,4}}
};
But this doesn't compile: Near to sizeof start it is saying invalid initialization.
What I'm really looking for is any way to store n arrays, where the first array can be compared to other arrays. The element preset in the arrays with be of varying size.
Your compile time error is that you're trying to use arr as a value to initialize arrayObject to. However, C only allows values that are known at compile time to be used as initializers. arr is an address on the stack that won't be known until execution time, therefore it can't be used as an initializer.
You should be able to initialize to sizeof arr/sizeof arr[0], which will be the count of elements in the array, but you can't initialize to arr, sizeof arr/sizeof arr[0].
The flaw in what you're trying to do is the way you're trying to distinguish between initialized vs. uninitialized elements.
int a[100] = { 1, 2 };
Does initialize all 100 elements. The elements not mentioned in the initializer list are initialized to zero. You can't use sizeof(a)/sizeof(a[0]) to count initialized elements.
You could do something like
#define INIT_LIST { 1, 2, 111} // 257
#define ASIZE 100
int big_array[ASIZE] = INIT_LIST;
// this works with gcc -O1 / -Og, but dummy is there in the object file at -O0
static const char dummy[] = INIT_LIST;
int initialized_count = sizeof(dummy); // sizeof(char) is guaranteed to be 1, so no divisor is needed.
// Or even better, no dummy array in the object file even with -O0:
int initialized_count2 = sizeof((int[])INIT_LIST)/sizeof(int);
// This also avoids compiler warnings when constants in the initializer list don't fit in a char.
// in macro form: Be careful with very large initializers; this could compile slowly if you used it all over the place.
#define COUNT_INITLIST (x) (sizeof((long[])x)/sizeof(long))
// Even with optimization on, this will also compile away to just returning a constant
int initialized_in_big_array() {
// without optimization: dummy2 is there in the object file
// but still not copied to the stack, because of const
const char dummy2[] = INIT_LIST;
return sizeof(dummy2);
}
It turns out even at low optimization levels like -Og, compilers avoid emitting unused arrays entirely. So the inline-function isn't needed. Jens Gustedt's suggestion of casting the initializer list, so there is never an array, is the best.
One solution is to put a sentinel value at the end of the array. For example, if negative values are not normally allowed in the array, then you could use the value -1 to mark the end of the array.
struct Arrays arrayObject[10]={
{{1,2,3,4,-1}},
{{1,3,5,6,3,4,-1}},
{{1,6,7,8,9,10,11,43,4,-1}}
};
This allows you to use a simple for loop to count the number of valid entries in the array.

Initializing multidimensional arrays in C

I'm just a tad confused about initializing multidimensional arrays in C...
This works:
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But this does not:
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
How come?
This syntax is for initialization, but in the second case you are using it for assignment which will not work.
type varName = someValue; // this is declaration and initialization
type varName; // this is declaration
varName = someValue; // this is assignment and not initialization
That is initialization can only be done at the declaration time, else it's a normal assignment.
The { syntax is only valid when you're initializing and declaring an array at the same time.
After declaring it, you need to use the complete syntax:
foo[0][0] = 2;
Technically speaking, C only has one-dimensional arrays. You create multidemnsional arrays by making arrays of arrays. The name of an array is converted to a pointer to its first element, and only the outer array is converted to a pointer. It's a pointer to an array of MAX ints, or int(*)[MAX].
As you said, this syntax is used to initialize an array, but in your second piece of code:
int foo[2][MAX];
Here, foo is uninitialized, and then
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
This is assignment, not initialization.
Multidimensional or not, arrays in C are not copyable, which means that there's no way to assign anything to the entire array using core language features after the initialization is complete.
However, it is still possible to copy arrays by using memcpy function. In combination with compound literals it allows you to do what you tried to do. You just have to use a different syntax
int foo[2][MAX];
memcpy(
foo,
(int[2][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
},
sizeof foo);
In C99 (or in gcc as an extension) you can make use of compound literals:
int (*foo)[MAX];
foo = (int [][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But note that foo must be declared as a pointer to MAX int's (not as a 2D array)
You have misunderstood the concept of 'initialization' and 'assignment`.
For example
int a = 10; // Initialization
Initialization is nothing but declaration + assignment.
But
int a; // Declaration
a = 10; // Assignment
When you do like this-
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
internally it came to know 2 rows and MAX columns. It will initialize the whole array.
But-
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
Here foo represent the starting address of the array. Here you are trying to assign the values to 2D array. when you are trying to assign values to array it doesn't know how many rows and how many columns are there. so it is not possible and not allowed.
When you want to assign the input to array A better solution is scan it from user/ at run time-
int foo[2][MAX],i,j;
for(i=0;i<2;i++){
for(j=0;j<max;j++)
scanf("%d",&foo[i][j]);
}

Initialization of a pointer array

I'm facing a problem initializing an array with pointers to members of a structure. The structure members have to be accessed through a structure pointer. The reason for this is we initialize the pointer at runtime to a memory mapped address location. The following code snippet is an example of the problem;
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
long* lp;
}T;
typedef struct
{
long l;
}F;
F* f;
T t[] =
{
{ &f->l }
};
void init (void)
{
f = (F*) 0x08000100;
}
int main (void)
{
init();
return EXIT_SUCCESS;
}
The compiler output is the following;
gcc -O0 -g3 -Wall -c
-fmessage-length=0 -osrc\Test.o ..\src\Test.c ..\src\Test.c:18:
error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0].lp')
..\src\Test.c:18: error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0]')
Build error occurred, build is stopped
The problem here is we initialize the pointer at runtime, the compiler doesn't know where it can find the structure members. We cannot work around the structure pointer as we don't wan't to use the linker script for this.
Any ideas how to get around this one?
T t[] =
{
{ &f->l }
};
The address of an element (e.g. &f->l) is only known at run-time.
Such a value cannot be used for compile-time initialization (which is what's being done here).
The t[] array cannot be filled out until runtime - because the address of F isn't known until runtime.
You could initialize T[] to {NULL} and patch it in post-init.
Another approach is to initialize the members of T to just simply be the offset within the structure, and after you init f, to walk through the array and adjust the pointer locations by adding the address of f. This technique is similar to what is often used in linking.
Something like this:
#define MEMBER_OFFSET_OF(a,b) &(((a*)0)->b)
T t[] =
{
{(long*)MEMBER_OFFSET_OF(F, l)}
};
const int numElementsInT = sizeof(t) / sizeof(t[0]);
void init()
{
f = (F*) 0x08000100;
for (int i= 0; i < numElementsInT; i++)
{
t[i].lp += (unsigned int)f;
}
}
Lets imagine that you could use non-constant data to initialize a global: you still have a huge problem.
When t is initialized, f still has an indeterminate value: this happens before init() executes and assigns your magic address. Because of this, even if you could use &f->l, you'd have to reset all places it's been used, anyway.
Technically speaking for a C90 compiler there is no way around this. For the initialization idiom,
declarator = initialization sequence
the initialization sequence needs to be a constant expression, i.e. one which can be computed at compile-time or at link-time. So,
int a;
int *b[] = { &a };
works, while
void foo() {
int a;
int *b[] = { &a };
}
will not because the address of the automatic a isn't computable before runtime.
If you switch to C99, the latter will work. Your code however still is beyond what a C99 compiler can precompute. If you switch to C++ your code would work, at least Comeau doesn't object.
Edit: of course Roger is correct in that this doesn't solve your problem of having an incorrect dereferencing through a NULL pointer.

Resources