user24723440
user24723440

Reputation: 563

In C language, are objects that are not explicitly initialized necessarily implicitly initialized?

The question I'm going to ask might be quite long. If possible, please read it through patiently. First of all, let's take a look at the content of §6.7.9 Initialization in C11:

¶8:

An initializer specifies the initial value stored in an object.

This indicates that when an object is created and it has an initial value, then this is initialization. Let's take a look at such a paragraph again:

¶19:

The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject;151) all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

Don't pay too much attention to the meaning of this sentence. We just need to know that there is the term "initialized implicitly" in C11.

Let's continue to look at p¶10:

¶10:

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

Based on these three sentences, we should be able to draw a conclusion: In C11, if an object with automatic storage duration is not explicitly initialized, it will be implicitly initialized, and the implicit initialization gives this object an indeterminate value;

Now let's take another look at the last sentence I will quote in C11:

¶9:

Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate value even after initialization.

I think this sentence is very strange. If unnamed members in a structure do not participate in initialization, then it should not participate in explicit initialization and implicit initialization. If so, how can the indeterminate value it has be explained?

Please remember the conclusion and a very strange point we obtained above, and let's take a look at the words in C23:

First of all, I can't find the sentence

An initializer specifies the initial value stored in an object.

in C23,6.7.11.

And a crucial point is that in C23, a wording was changed: It changed "value" to "representation": Just like the paragraph in p10 of C23 corresponding to the paragraph in ¶9 of the previous C11:

¶10:

Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate representation even after initialization.

Secondly, I didn't find any relevant statements about "implicit initialization" in C23. The corresponding sentence to ¶19 in the previous C11 in C23 is:

¶20:

The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject;170) all subobjects that are not initialized explicitly are subject to default initialization.

According to C23:

¶2:

An empty brace pair ({}) is called an empty initializer and is referred to as empty initialization.

and

¶11:

If an object that has static or thread storage duration is not initialized explicitly, or any object is initialized with an empty initializer, then it is subject to default initialization, which initializes an object as follows...

So there are three kinds of initializations in C23: explicit, empty initialization and default initialization.

In this way, it seems to make sense about the strange point earlier: C23 does not call all the initial values obtained when creating objects as initialization. Because in C23, there is no rule (at least I can't find it) that the indeterminate "representation" obtained by objects with automatic storage duration that are not explicitly initialized is regarded as a kind of "initialization". From this perspective, it is not strange that unnamed objects in structures and union types do not participate in initialization. They can have an indeterminate "representation" without going through initialization.

Are the words in C11 ambiguous? Is there any problem with my reasoning?

I need to thank you first. Anyway, it's already worthy of my gratitude that you can read up to here.

Upvotes: 1

Views: 169

Answers (3)

John Bollinger
John Bollinger

Reputation: 181199

An initializer specifies the initial value stored in an object.

[...]

The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject;151) all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

[...]

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

Based on these three sentences, we should be able to draw a conclusion: In C11, if an object with automatic storage duration is not explicitly initialized, it will be implicitly initialized, and the implicit initialization gives this object an indeterminate value;

No, that conclusion does not follow from the given sentences nor from anything else in the spec. You seem to be relying on an assumption that the only way an object can have a value, even an indeterminate one, is for that object to have been initialized. But a more consistent and conventional reading of the spec is that having an indeterminate value is a consequence of not having been initialized at all. This is the spec's way of modeling what, in practice, is usually that whatever happens to have already been in the memory occupied by the object stays there, and those bytes may or may not be interpretable according to the object's type.

And this speaks to the following point of confusion:

If unnamed members in a structure do not participate in initialization, then it should not participate in explicit initialization and implicit initialization. If so, how can the indeterminate value it has be explained?

Indeed. If having an indeterminate value were the result of having been initialized, implicitly or otherwise, then the provision in question would not make sense. But the provision makes perfect sense when you understand that instead, objects with automatic storage duration having indeterminate values is the natural outcome of them not having been initialized at all.

First of all, I can't find the sentence

An initializer specifies the initial value stored in an object.

in C23,6.7.11.

Could that be because you should be looking in section 6.7.10, "Initialization"? The sentence you're talking about is the first in paragraph 9.

a wording was changed: It changed "value" to "representation"

This is of no special consequence. The committee perceived some issues with the spec's usage of the term "indeterminate value". All usage of that term is removed in C23, with most appearances replaced by the term "indeterminate representation", defined as:

object representation that either represents an unspecified value or is a non-value representation

If you've been reading the specs closely, you may notice that the term "trap representation" is now gone, too, in favor of "non-value representation". You should not read anything into these changes, certainly not with respect to object initialization.

So there are three kinds of initializations in C23: explicit, empty initialization and default initialization.

Sort of. These are not parallel. Empty initialization is best understood as syntax for specifying that an object should be initialized according to the rules for default initialization. It can plausibly be considered a form of explicit initialization, though the spec does seem to distinguish. Inb the other hand, default initialization is semantic, describing what initial values certain objects take. And explicit initialization has both syntactic and semantic aspects.

In this way, it seems to make sense about the strange point earlier: C23 does not call all the initial values obtained when creating objects as initialization.

That is correct, but neither does C11.

Because in C23, there is no rule (at least I can't find it) that the indeterminate "representation" obtained by objects with automatic storage duration that are not explicitly initialized is regarded as a kind of "initialization".

Neither is there such a rule in C11. You made that up all by yourself, as I have already described, and that reading is inconsistent with other parts of the spec.

From this perspective, it is not strange that unnamed objects in structures and union types do not participate in initialization. They can have an indeterminate "representation" without going through initialization.

Exactly as they can in C11.

Are the words in C11 ambiguous?

I don't find them so. At least not in this particular regard. The idea of "indeterminate value" is a bit weird, but I don't think the change to "indeterminate representation" is any kind of substantial shift. But if you find the latter clearer, though, then that speaks well for the committee's decision to make that change.

Is there any problem with my reasoning?

Yes, see above.

Upvotes: 2

Eric Postpischil
Eric Postpischil

Reputation: 223795

First, there is no value that is an indeterminate value. Indeterminate value is a notional semantic state. When the C standard says an object has an indeterminate value, it means there is no requirement that the memory of the object be given any contents nor that any use of that memory needs to be made to retrieve the value of the object and that any attempt to use the value of the object produces a similar state of indeterminate value. (For example, if x has an indeterminate value, then x + 3 also has an indeterminate value.)

It might have been better if the C standard had used other language, such as saying that, if an object is not initialized, the program is not required to use any particular value for it on any occasion.

Based on these three sentences, we should be able to draw a conclusion: In C11, if an object with automatic storage duration is not explicitly initialized, it will be implicitly initialized, and the implicit initialization gives this object an indeterminate value;

This is not correct. If an object is not initialized, nothing is done for it. (Specifically, the C standard does not specify that anything is done for it. A C implementation could choose to do something.) Further, when an object has an indeterminate value, the C implementation is relieved of any obligation regarding the value. For example, in y = x + 3;, if x has a value, then, in the process of executing this statement, the value of x is retrieved from memory (in the abstract computer model the C standard uses to specify program semantics). If x has an indeterminate value, the C implementation is not required to load anything from memory for this lvalue conversion. It can use any value, such as a value the program happens to have in a register where the value would have been loaded from memory. And it can use a different value each time x is used. (The value of x is not determined. It can be different each time we try to use it; there is no determined value. It is indeterminate.)

I think this sentence is very strange. If unnamed members in a structure do not participate in initialization, then it should not participate in explicit initialization and implicit initialization. If so, how can the indeterminate value it has be explained?

This conundrum arises solely from the incorrect statement above that an uninitialized object is implicitly initialized. An unnamed member of a structure with an indeterminate value is the same as an object with an indeterminate value: The C standard does not require its memory be set to anything and does not require that a C implementation do anything to retrieve a value from memory.

If an object that has static or thread storage duration is not initialized explicitly, or any object is initialized with an empty initializer, then it is subject to default initialization, which initializes an object as follows...

So there are three kinds of initializations in C23: explicit, empty initialization and default initialization.

No, an empty initializer is one form of explicit initialization.

Upvotes: 3

dbush
dbush

Reputation: 224882

Regarding C11 6.7.9p19, there's some important context you missed in paragraph 12:

The rest of this subclause deals with initializers for objects that have aggregate or union type.

So paragraph 19 applies to structs, unions, and arrays. A specific example it applies to is as follows:

int x[5] = { 10, 20, 30 };

Here, array elements 0, 1, and 2 are explicitly initialized with the values 10, 20, and 30 respectively. Elements 3 and 4 of the array are then implicitly initialized with the value 0, just like an object of type int that was defined at file scope without an initializer. The idea here is that an object isn't partially initialized.

This is in contrast to the following declaration at block scope:

int y;

Where y is uninitialized and therefore its value is indeterminate.

Also, the word "uninitialized" appears with a description in C11 6.3.2.1p2:

If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

So "implicitly initialized" and "uninitialized" are two different things.

Upvotes: 7

Related Questions