[Note] The body of the C language array

I was always misunderstanding.

int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };

When the array ʻarrayis defined [^ _1] in this way, the{0, 1, ..., 9,}to the right of the substitution symbol=` that specifies its initial value is also an "array". That's it.

[^ _1]: defintion. Writing like ʻint array [10];` is a declaration, and writing including that value is a definition (definition). However, according to Wikipedia, definition and declaration are not distinguished in C ++ (or rather the same [^ _2]).

[^ _3]: (Private translation) Many people find it convenient to distinguish between "declaration" and "definition". This can be seen in the mundane phrase "the difference between a declaration and a definition is ~", and it is said that a declaration is just a specification of a data object (or function). By the way, according to the C ++ standard, the definition is the same as the declaration. However, even though it is formally inaccurate, the phrase "declaration and definition" is overwhelming to the population.

It wasn't.

Array definition and initialization list

In C language grammar, the part [^ _4] surrounded by braces on the right side of ʻint array [] = {...} `is called the" initialization list "[^ _5].

[^ _4]: I would like to call it an object, but I think the definition used to initialize a variable is probably not an object. If you can refer to the standard ...

[^ _5]: I'd really like to write "according to the C99 standard" here, but I don't have it, so I'm using it in hearsay. I'm sorry.

Therefore, the array exists (only) in the declaration part (that is, ʻint array [...] `). In other words, there is no array on the right side of the assignment operator [^ _6].

[^ _6]: Wait a minute, then what is = in the definition? I think I can hear the voice. I'm sorry I couldn't refer to the grammar of the standard, but I think that the assignment symbol in the definition is just the "definition" of the initial value, not the assignment.

This can also be confirmed by the following code snippet causing a compilation error.

int a[3] = { 0, 1, 2, };
int b[3] = a;
error: array initializer must be an initializer list or wide string literal
  int b[3] = a;
      ^

Also, the array cannot be an lvalue. (Substitution is not allowed)

int a[3] = { 0, 1, 2, };
int b[3];
b = a;

When I try to compile this code, I get the following error:

error: array type 'int [3]' is not assignable
  b = a;
  ~ ^

Forcible substitution operation

It's a derailment, but you can (force) copy the values in an array, assuming you know the size of the array.

struct array_copy {
  int xs[3];
};

int a[3] = {0, 1, 2,};
int b[3];

*(struct array_copy*)b = *(struct array_copy*)a;

Since an array can be regarded as both an address and a pointer, it is a bad hack to cast to a structure that contains an array and transfer the contents using the assignment of the structure [^ _7].

[^ _7]: However, it is not practical. If you know that you're going to use an array of the same size, it's best to give it a "type" as a structure in advance.

Composite literal

In addition, C99 has "compound literal (compound literal)" (it has the appearance of prefixing the type in the initialization list). ..

Composite literals allow you to define "anonymous" arrays "on the fly".

memcpy(b, (int[3]){ 2, 1, 0, }, sizeof(b));

Array initialization and (array) composite literals

In the previous array initialization, the array could not be initialized with an array (with a compilation error).

However, with gcc 4.2.1 (Apple LLVM version 9.1.0 (clang-902.0.39.2)), the following code can be compiled without warning.

int a[] = (int[3]) { 4, 5, 6, };

Defining arrays with compound literals seems legal [^ _5].

(Array) Assignment to a compound literal element

I don't know what it means in practice, but you can do this [^ compound_assignmemnt].

(int[]){ 0, 1, 2, 3, 4, }[2] = 8;

When I do this for string literals (ie something like " hello "[0] ='H';), something strange happens (probably causing undefined behavior [^ _ 5]).

[^ compound_assignmemnt]: By the way, the assignment statement has the result (evaluation result) of executing the assignment operation as the "value". The statement of assigning a value to an element of an array compound literal has the value assigned to that element as the evaluation result, so it becomes even more difficult to understand its practical meaning. In other words, since a compound literal is "anonymous", as a result of assignment to the element, there is no way to access the array (composite literal) itself that stores the element.

Address of a compound literal

Composite literals seem to secure an entity as an object on the fly [^ _5].

So if you compile and run the following, it will print Woo-foo [^ const_arrays_has_different_address_too].

int *pa = (int[3]){ 0, 1, 2, };
int *pb = (int[3]){ 0, 1, 2, };
if (pa != pb) puts("Woo-foo!");

[^ const_arrays_has_different_address_too]: (const int []) {0} == (const int []) {0} is also false. String literals are immutable objects (compatible with type const char []), and string literals with the same value in the same translation unit have the same address (" hello "==" hello " is true I thought that if I gave a hint that it was an immutable array, it might refer to the same address. (It may be the same depending on the processing system and optimization level)

On the other hand, string literals that exist in the same translation unit have the same address.

const char *ps = "hello";
if (ps != "hello") puts("Woo-foo!");

Nothing is printed even if this is translated and executed [^ _8].

[^ _8]: In C language, string literal operations are supposed to be via the string function (unlike other built-in types), so how meaningful is object identity checking by address comparison? Please do not ask at this time.

Recommended Posts