Malformed C/C++ Multidimensional Array Initialization in GCC

后端 未结 1 1009
长情又很酷
长情又很酷 2021-01-24 21:37

I think I get how padding works with a proper format, i.e. this:

char arr[3][2] = {{1}, {4,5}};

is equivalent to

char arr[3][2] = {1, 0,

相关标签:
1条回答
  • 2021-01-24 21:54

    C 2018 6.7.9 paragraphs 17 to 21 discuss how aggregates are initialized from brace-enclosed lists. 17 says:

    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. In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.

    20 tells us about contained arrays:

    If the aggregate or union contains elements or members that are aggregates or unions, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the contained union. Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.

    21 tells us about missing initializers:

    If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

    Now we can see how char arr[3][3] = {{1,2,3},12,{4,5,6}}; is processed.

    First, we are initializing arr, so, by paragraph 17, we will initialize its three elements, arr[0], arr[1], and arr[2], in order. Since the first item in the list {1,2,3}, 12, {4,5,6} is a brace-enclosed list, paragraph 20 tells us that the items in that list, {1,2,3} will be used to initialize the subaggregate arr[0].

    So arr[0][0], arr[0][1], and arr[0][2] are initialized to 1, 2, and 3.

    Next, we consider arr[1]. The initializer for arr[1] starts with 12, not with a left brace, so we are not taking initializers from a brace-enclosed list. So we have two items left in the list, 12 and {4,5,6}, to use for initializing arr[1][0], arr[1][1], and arr[1][2] (and, later, the elements of arr[2]).

    So 12 initializes arr[1][0], producing 12, of course. Then {4,5,6} initializes arr[1][1].

    There are two problems here. One is that the rules in paragraph 20 says that if we are initializing a subaggregate with a brace-enclosed list, the initializers in the list are used for the elements or members of the subaggregate. But we are attempting to initialize arr[1][1], and it is a scalar object, not an aggregate. So the rules do not tell us what to do. I believe the behavior is not defined.

    Further, if we do take this brace-enclosed list to be supplying initial values, it has too many values, and this may also be undefined because paragraph 2 says:

    No initializer shall attempt to provide a value for an object not contained within the entity being initialized.

    Regardless of the lack of definition, it appears GCC has taken the first item of the brace-enclosed list to initialize arr[1][1] and discarded the rest. This seems reasonable. In contrast, taking the 5 and 6 to initialize other array elements seems less reasonable: Due to the processing specified by the C standard, the entire brace-enclosed list has been associated with arr[1][1], and there is no reason to take values from that list to use for other array elements.

    Assuming the compiler continues after the undefined behavior, there are no initializers for arr[1][2], and the elements of arr[2]. So the rule in paragraph 21 about missing initializers applies: They are initialized as if for a static object, which, for a char, means they are initialized to zero.

    0 讨论(0)
提交回复
热议问题