Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens in the background of array initialization in c?

Given that this is legal

uint8_t bytes[4] = { 1, 2, 3, 4 };

And this is not:

uint8_t bytes2[4];
bytes2 = { 1, 2, 3, 4 };

what does { 1, 2, 3, 4 } represent?

Am assuming it's neither an rvalue or an lvalue. A preprocessor code candy that expands to something?

like image 359
TheMeaningfulEngineer Avatar asked Jul 05 '17 10:07

TheMeaningfulEngineer


2 Answers

A syntax like {1,2,3,4}; is called brace-enclosed initializer list, it's an initializer. It can be only used for initialization (for array type).

Quoting C11, chapter §6.7.9

  • P11

The initializer for a scalar shall be a single expression,

[an array is not a scalar type, so not applicable for us]

  • P14

An array of character type may be initialized by a character string literal or UTF−8 string literal, optionally enclosed in braces.

[We are not using a string literal here, so also not applicable for us]

  • P16

Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.

[This is the case of our interest]

and, P17,

Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union.[....]

So, here, the values from the brace enclosed list are not directly "assigned" to the array, they are used to initialize individual members of the array.

OTOH, an array type, is not a modifiable lvalue, so it cannot be assigned. In other words, an array variable cannot be used as the LHS of the assignment operator.

To elaborate, from C11, chapter §6.5.16

assignment operator shall have a modifiable lvalue as its left operand.

like image 147
Sourav Ghosh Avatar answered Nov 15 '22 07:11

Sourav Ghosh


{1,2,3,4} is an initializer-list, a particular syntax token that can only be used on the line where the array is declared.

This is regulated purely by the C standard syntax. There's no particular rationale behind it, this is just how the language is defined. In the C syntax, arrays cannot be assigned to, nor copied by assignment.

You can however dodge the syntax restrictions in several ways, to overwrite all values at once. The simplest way is just to create a temporary array and memcpy:

uint8_t tmp[] = {5,6,7,8};
memcpy(bytes, tmp, sizeof bytes);

Alternatively, use a compound literal:

memcpy(bytes, (uint8_t[]){5,6,7,8}, sizeof bytes);

If it makes sense for the specific application, you can also wrap the array in a struct to bypass the syntax restrictions:

typedef struct
{
  uint8_t data [4];
} array_t;

...

array_t bytes = { .data = {1,2,3,4} };
array_t tmp   = { .data = {5,6,7,8} };
bytes = tmp; // works just fine, structs can be copied this way
like image 39
Lundin Avatar answered Nov 15 '22 07:11

Lundin