Is subscribing to an array subscribed to the address of the object?

This question is inspired by the answers to this question .

The following code has the potential for undefined behavior:

uint64_t arr[1]; // Uninitialized if(arr[0] == 0) { 

Standard C indicates that an uninitialized variable with automatic storage duration has an indefinite value that is either indeterminate or trap. He also points out that the uintN_t types do not have padding bits, and the size and range of values ​​are well defined; therefore, a trap view for uint64_t not possible.

So, I came to the conclusion that the uninitialized value itself is not undefined behavior. How about reading it?

6.3.2.1 Lvalues, arrays, and function notation

  • ...
  • Unless it is an operand of the sizeof operator, the _Alignof operator, unary and operator, ++ operator, operator -- or left operand. operator or assignment operator, the value of l, which does not have the type of an array, is converted to the value stored in the specified object (and is no longer an lvalue); this is called an lvalue conversion ....

    ... If lvalue denotes an object with an automatic storage duration that could be declared with a register storage class (its address was never accepted) and this object is uninitialized (not declared with the initializer and its assignment is not performed) before use), the behavior is undefined .

  • Unless it is an operand of the sizeof operator, the _Alignof operator is either unary and the operator, or is a string literal used to initialize the array, an expression that has type '' of type type is converted to an expression with a type pointer '' to type such points to the original element of the array object and is not an lvalue value. If the array object has a register storage class, the behavior is undefined.

Question: Is the subscript array taken into account as the receiving address of the object?

The following text seems to imply that a sub-pixel array requires conversion to a pointer, which seems impossible without an address:

6.5.2.1 Substring Array

Limitations

  • One of the expressions must have a type pointer '' to complete the type of the object, the other expression must have an integer type, and the result is of type type.

Semantics

  1. A postfix expression followed by an expression in square brackets [] is the indexed designation of an element of an array object. The definition of the index operator [] that E1 [E2] is identical (* ((E1) + (E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the starting element of an array object) and E2 is an integer, E1 [E2] stands for E2 is an element of E1 (counting from zero).

This makes clause 6.3.2.1 of clause 3 seem strange. How could an array have a data storage class at all if the subscription needs to be converted to a pointer?

+5
source share
2 answers

Yes, counting the signatures of the array is considered the address specified in clause 6.5.2.1. The expression E1 must have its address.

Therefore, the special case of UB in 6.3.2.1 does not apply to array indexing. If array indices are used, it does not matter if the array can be stored with register storage duration or not (a variable with its own address cannot use register storage duration).

You think it is right to assume that reading an uninitialized type stdint.h with an undefined value that has its own address does not cause undefined behavior (guaranteed by C11 7.20.1.1), but simply undefined behavior. The value can be anything, and it can be non-deterministic between several readings, but it cannot be a trap.

"Reading an uninitialized variable is always UB" is a widespread but incorrect myth. Further information with regulatory sources in this answer .

+6
source

The lvalues ​​discussed in section 6.3.2.1 can never be elements of an array declared with register , so the question of what their addresses mean never arises.

In paragraph 3, using an array declared with register , except as an operand of sizeof , _Alignof or & has undefined behavior. But the only way to get an lvalue for an array element is to use the array differently from arr[0] .

Therefore, it can never happen (with a specific behavior) that the lvalue discussed in paragraph 2 denotes an element of an array that could be declared with a register storage class.

In this light, the bracketed comment “has never been accepted” is clear. It applies only to objects that are not elements of the array, and the only way to create an address for such an object is to apply & . 1 Taking an address means using & .

Regardless of whether the evaluation is arr[0] or arr + 2 or even just arr (as in arr; and not as a sizeof operand or something else), then accepting the address of an array element does not matter. This does not affect what 6.3.2.1 means 2.

Regarding your question about how an array can have a register storage class, note 121 (in section 6.7.1) says: “Thus, the only operators that can be applied to an array declared using the register of a storage class specifier are sizeof and _Alignof. " (Although this is legal, it does not seem useful, since you can use sizeof and _Alignof without using register , so including register in the declaration does not seem to provide any useful property.)

Footnote

1 The exception is that in paragraph 6.7.2.1 in paragraph 15 it is said that a pointer to a structure can be converted to a pointer to its first member, and in paragraph 16 it is indicated that a pointer to a union can be converted to a pointer to any of its members . However, this requires an indication of the pointer to the collection (structure or union), which means that the aggregate itself cannot have a register storage class, and members inside the aggregate cannot be declared a storage class.

0
source

Source: https://habr.com/ru/post/1274184/