Confusion about array initialization in C

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
87
down vote

favorite
12












In C language, if initialize an array like this:



int a[5] = 1,2;


then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.



But, if I initialize an array like this:



int a[5]=a[2]=1;

printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);


output:



1 0 1 0 0


I don't understand, why does a[0] print 1 instead of 0? Is it undefined behaviour?



Note: This question was asked in an interview.










share|improve this question



















  • 31




    The expression a[2]=1 evaluates to 1.
    – tkausl
    Sep 13 at 6:01






  • 14




    A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
    – Bathsheba
    Sep 13 at 6:59







  • 15




    Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
    – Bathsheba
    Sep 13 at 7:04







  • 1




    @Bathsheba I would do the opposite, as the answer here now answers both questions.
    – Kami Kaze
    Sep 13 at 7:36






  • 1




    @Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
    – Kami Kaze
    Sep 13 at 7:39















up vote
87
down vote

favorite
12












In C language, if initialize an array like this:



int a[5] = 1,2;


then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.



But, if I initialize an array like this:



int a[5]=a[2]=1;

printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);


output:



1 0 1 0 0


I don't understand, why does a[0] print 1 instead of 0? Is it undefined behaviour?



Note: This question was asked in an interview.










share|improve this question



















  • 31




    The expression a[2]=1 evaluates to 1.
    – tkausl
    Sep 13 at 6:01






  • 14




    A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
    – Bathsheba
    Sep 13 at 6:59







  • 15




    Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
    – Bathsheba
    Sep 13 at 7:04







  • 1




    @Bathsheba I would do the opposite, as the answer here now answers both questions.
    – Kami Kaze
    Sep 13 at 7:36






  • 1




    @Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
    – Kami Kaze
    Sep 13 at 7:39













up vote
87
down vote

favorite
12









up vote
87
down vote

favorite
12






12





In C language, if initialize an array like this:



int a[5] = 1,2;


then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.



But, if I initialize an array like this:



int a[5]=a[2]=1;

printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);


output:



1 0 1 0 0


I don't understand, why does a[0] print 1 instead of 0? Is it undefined behaviour?



Note: This question was asked in an interview.










share|improve this question















In C language, if initialize an array like this:



int a[5] = 1,2;


then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.



But, if I initialize an array like this:



int a[5]=a[2]=1;

printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);


output:



1 0 1 0 0


I don't understand, why does a[0] print 1 instead of 0? Is it undefined behaviour?



Note: This question was asked in an interview.







c arrays initialization language-lawyer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 13 at 14:28









Jesse de Bruijne

2,29631125




2,29631125










asked Sep 13 at 5:58









rsp

17.5k455115




17.5k455115







  • 31




    The expression a[2]=1 evaluates to 1.
    – tkausl
    Sep 13 at 6:01






  • 14




    A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
    – Bathsheba
    Sep 13 at 6:59







  • 15




    Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
    – Bathsheba
    Sep 13 at 7:04







  • 1




    @Bathsheba I would do the opposite, as the answer here now answers both questions.
    – Kami Kaze
    Sep 13 at 7:36






  • 1




    @Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
    – Kami Kaze
    Sep 13 at 7:39













  • 31




    The expression a[2]=1 evaluates to 1.
    – tkausl
    Sep 13 at 6:01






  • 14




    A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
    – Bathsheba
    Sep 13 at 6:59







  • 15




    Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
    – Bathsheba
    Sep 13 at 7:04







  • 1




    @Bathsheba I would do the opposite, as the answer here now answers both questions.
    – Kami Kaze
    Sep 13 at 7:36






  • 1




    @Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
    – Kami Kaze
    Sep 13 at 7:39








31




31




The expression a[2]=1 evaluates to 1.
– tkausl
Sep 13 at 6:01




The expression a[2]=1 evaluates to 1.
– tkausl
Sep 13 at 6:01




14




14




A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
– Bathsheba
Sep 13 at 6:59





A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression a[2] = 1 is 1, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
– Bathsheba
Sep 13 at 6:59





15




15




Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
Sep 13 at 7:04





Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
Sep 13 at 7:04





1




1




@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
Sep 13 at 7:36




@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
Sep 13 at 7:36




1




1




@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
Sep 13 at 7:39





@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
Sep 13 at 7:39













7 Answers
7






active

oldest

votes

















up vote
85
down vote



accepted










TL;DR: I don't think the behavior of int a[5]=a[2]=1; is well defined, at least in C99.



The funny part is that the only bit that makes sense to me is the part you're asking about: a[0] is set to 1 because the assignment operator returns the value that was assigned. It's everything else that's unclear.



If the code had been int a[5] = [2] = 1 , everything would've been easy: That's a designated initializer setting a[2] to 1 and everything else to 0. But with a[2] = 1 we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.




Here's what I've found so far:




  • a must be a local variable.




    6.7.8 Initialization



    1. All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.



    a[2] = 1 is not a constant expression, so a must have automatic storage.




  • a is in scope in its own initialization.




    6.2.1 Scopes of identifiers



    1. Structure, union, and enumeration tags have scope that begins just after the appearance of
      the tag in a type specifier that declares the tag. Each enumeration constant has scope that
      begins just after the appearance of its defining enumerator in an enumerator list. Any
      other identifier has scope that begins just after the completion of its declarator.




    The declarator is a[5], so variables are in scope in their own initialization.




  • a is alive in its own initialization.




    6.2.4 Storage durations of objects



    1. An object whose identifier is declared with no linkage and without the storage-class
      specifier static has automatic storage duration.


    2. For such an object that does not have a variable length array type, its lifetime extends
      from entry into the block with which it is associated until execution of that block ends
      in
      any way. (Entering an enclosed block or calling a function suspends, but does not end,
      execution of the current block.) If the block is entered recursively, a new instance of the
      object is created each time. The initial value of the object is indeterminate. If an
      initialization is specified for the object, it is performed each time the declaration is
      reached in the execution of the block; otherwise, the value becomes indeterminate each
      time the declaration is reached.





  • There is a sequence point after a[2]=1.




    6.8 Statements and blocks



    1. A full expression is an expression that is not part of another expression or of a declarator.
      Each of the following is a full expression: an initializer; the expression in an expression
      statement; the controlling expression of a selection statement (if or switch); the
      controlling expression of a while or do statement; each of the (optional) expressions of
      a for statement; the (optional) expression in a return statement. The end of a full
      expression is a sequence point.




    Note that e.g. in int foo = 1, 2, 3 the 1, 2, 3 part is a brace-enclosed list of initializers, each of which has a sequence point after it.




  • Initialization is performed in initializer list order.




    6.7.8 Initialization



    1. 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. [...]

     



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




  • However, initializer expressions are not necessarily evaluated in order.




    6.7.8 Initialization



    1. The order in which any side effects occur among the initialization list expressions is
      unspecified.




However, that still leaves some questions unanswered:




  • Are sequence points even relevant? The basic rule is:




    6.5 Expressions



    1. Between the previous and next sequence point an object shall have its stored value
      modified at most once by the evaluation of an expression. Furthermore, the prior value
      shall be read only to determine the value to be stored.



    a[2] = 1 is an expression, but initialization is not.



    This is slightly contradicted by Annex J:




    J.2 Undefined behavior



    • Between two sequence points, an object is modified more than once, or is modified
      and the prior value is read other than to determine the value to be stored (6.5).



    Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.



  • How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?



I think int a[5] = a[2] = 1 is executed as follows:



  1. Storage for a is allocated when its containing block is entered. The contents are indeterminate at this point.

  2. The (only) initializer is executed (a[2] = 1), followed by a sequence point. This stores 1 in a[2] and returns 1.

  3. That 1 is used to initialize a[0] (the first initializer initializes the first subobject).

But here things get fuzzy because the remaining elements (a[1], a[2], a[3], a[4]) are supposed to be initialized to 0, but it's not clear when: Does it happen before a[2] = 1 is evaluated? If so, a[2] = 1 would "win" and overwrite a[2], but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2] should end up being 0.



Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).






share|improve this answer


















  • 1




    Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
    – Some programmer dude
    Sep 13 at 8:24






  • 1




    "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
    – BЈовић
    Sep 13 at 9:16






  • 2




    @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
    – melpomene
    Sep 13 at 15:52






  • 2




    @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
    – gnasher729
    Sep 13 at 22:40






  • 1




    @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
    – melpomene
    Sep 14 at 19:41

















up vote
21
down vote














I don't understand, why does a[0] print 1 instead of 0?




Presumably a[2]=1 initializes a[2] first, and the result of the expression is used to initialize a[0].



From N2176 (C17 draft):




6.7.9 Initialization



  1. The evaluations of the initialization list expressions are indeterminately sequenced with respect to
    one another and thus the order in which any side effects occur is unspecified. 154)



So it would seem that output 1 0 0 0 0 would also have been possible.



Conclusion: Don't write initializers that modifies the initialized variable on the fly.






share|improve this answer


















  • 1




    That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
    – melpomene
    Sep 13 at 7:43










  • @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
    – user694733
    Sep 13 at 7:47






  • 1




    ... is a braced initializer list. It is not an expression.
    – melpomene
    Sep 13 at 7:49










  • @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
    – user694733
    Sep 13 at 8:03










  • @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
    – M.M
    Sep 13 at 9:01

















up vote
5
down vote













I think the C11 standard covers this behaviour and says that the result
is unspecified, and I don't think C18 made any relevant changes in
this area.



The standard language is not easy to parse.
The relevant section of the standard is
§6.7.9 Initialization.
The syntax is documented as:




initializer:

                assignment-expression

                 initializer-list

                 initializer-list ,
initializer-list:

                designationopt initializer

                initializer-list , designationopt initializer
designation:

                designator-list =
designator-list:

                designator

                designator-list designator
designator:

                [ constant-expression ]

                . identifier




Note that one of the terms is assignment-expression, and since a[2] = 1 is indubitably an assignment expression, it is allowed inside
initializers for arrays with non-static duration:




§4 All the expressions in an initializer for an object that has
static or thread storage duration shall be constant expressions or
string literals.




One of the key paragraphs is:




§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.



151) Any initializer for the subobject which is overridden
and so not used to initialize that subobject might not be evaluated at
all.




And another key paragraph is:




§23 The evaluations of the initialization list expressions are
indeterminately sequenced with respect to one another and thus the
order in which any side effects occur is unspecified.152)



152) In particular, the evaluation order need not be the
same as the order of subobject initialization.




I'm fairly sure that paragraph §23 indicates that the notation in the
question:



int a[5] = a[2] = 1 ;


leads to unspecified behaviour.
The assignment to a[2] is a side-effect, and the evaluation order of the
expressions are indeterminately sequenced with respect to one another.
Consequently, I don't think there is a way to appeal to the standard and
claim that a particular compiler is handling this correctly or incorrectly.






share|improve this answer





























    up vote
    3
    down vote













    My Understanding is
    a[2]=1 returns value 1 so code becomes



    int a[5]=a[2]=1 --> int a[5]=1


    int a[5]=1 assign value for a[0]=1



    Hence it print 1 for a[0]



    For example



    char str[10]=‘H’,‘a’,‘i’;


    char str[0] = ‘H’;
    char str[1] = ‘a’;
    char str[2] = ‘i;





    share|improve this answer
















    • 1




      This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
      – Kami Kaze
      Sep 14 at 8:20











    • I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
      – Karthika
      Sep 14 at 9:56










    • You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
      – Kami Kaze
      Sep 14 at 10:00










    • But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
      – Karthika
      Sep 14 at 10:23











    • OP asked "Is it undefined behaviour?". Your answer doesn't say.
      – melpomene
      Sep 14 at 12:12

















    up vote
    1
    down vote













    I try to give a short and simple answer for the puzzle: int a[5] = a[2] = 1 ;



    1. First a[2] = 1 is set. That means the array says: 0 0 1 0 0

    2. But behold, given that you did it in the brackets, which are used to initialize the array in order, it takes the first value (which is 1) and sets that to a[0]. It is as if int a[5] = a[2] ; would remain, where we already got a[2] = 1. The resulting array is now: 1 0 1 0 0

    Another example: int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ; - Even though the order is somewhat arbitrary, assuming it goes from left to right, it would go in these 6 steps:



    0 0 0 1 0 0
    1 0 0 1 0 0
    1 0 0 1 2 0
    1 2 0 1 2 0
    1 2 0 1 2 3
    1 2 3 1 2 3





    share|improve this answer


















    • 1




      A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
      – melpomene
      Sep 13 at 15:48






    • 1




      "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
      – melpomene
      Sep 14 at 12:14






    • 1




      "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
      – melpomene
      Sep 14 at 14:49






    • 1




      The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
      – John Bollinger
      Sep 14 at 15:02







    • 1




      "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
      – Jeroen Mostert
      Sep 14 at 16:04

















    up vote
    0
    down vote













    The assignment a[2]= 1 is an expression that has the value 1, and you essentially wrote int a[5]= 1 ; (with the side effect that a[2] is assigned 1 as well).






    share|improve this answer



























      up vote
      -3
      down vote













      Order of operations.



      First, the assignment occurs and the assignment is evaluated as this:



      int a[5] = 1, which yields the following:



      1, 0, 0, 0, 0. We get 1 because a[2]=1 evaluates to true and is implicitly cast to 1 in the assignment series.



      Second, the expression within the curly brackets is executed, which results in actually assigning 1 to the array at index 2.



      You can experiment by compiling int a[5]=true; and also int a[5]=a[3]=3; and observing the results.



      edit: I was wrong about the result of the assignment within the initialization list, that results in an integer that is the same as what was assigned.






      share|improve this answer






















      • This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
        – Kami Kaze
        Sep 14 at 8:19







      • 1




        "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
        – melpomene
        Sep 14 at 12:10










      Your Answer





      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52307474%2fconfusion-about-array-initialization-in-c%23new-answer', 'question_page');

      );

      Post as a guest






























      7 Answers
      7






      active

      oldest

      votes








      7 Answers
      7






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      85
      down vote



      accepted










      TL;DR: I don't think the behavior of int a[5]=a[2]=1; is well defined, at least in C99.



      The funny part is that the only bit that makes sense to me is the part you're asking about: a[0] is set to 1 because the assignment operator returns the value that was assigned. It's everything else that's unclear.



      If the code had been int a[5] = [2] = 1 , everything would've been easy: That's a designated initializer setting a[2] to 1 and everything else to 0. But with a[2] = 1 we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.




      Here's what I've found so far:




      • a must be a local variable.




        6.7.8 Initialization



        1. All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.



        a[2] = 1 is not a constant expression, so a must have automatic storage.




      • a is in scope in its own initialization.




        6.2.1 Scopes of identifiers



        1. Structure, union, and enumeration tags have scope that begins just after the appearance of
          the tag in a type specifier that declares the tag. Each enumeration constant has scope that
          begins just after the appearance of its defining enumerator in an enumerator list. Any
          other identifier has scope that begins just after the completion of its declarator.




        The declarator is a[5], so variables are in scope in their own initialization.




      • a is alive in its own initialization.




        6.2.4 Storage durations of objects



        1. An object whose identifier is declared with no linkage and without the storage-class
          specifier static has automatic storage duration.


        2. For such an object that does not have a variable length array type, its lifetime extends
          from entry into the block with which it is associated until execution of that block ends
          in
          any way. (Entering an enclosed block or calling a function suspends, but does not end,
          execution of the current block.) If the block is entered recursively, a new instance of the
          object is created each time. The initial value of the object is indeterminate. If an
          initialization is specified for the object, it is performed each time the declaration is
          reached in the execution of the block; otherwise, the value becomes indeterminate each
          time the declaration is reached.





      • There is a sequence point after a[2]=1.




        6.8 Statements and blocks



        1. A full expression is an expression that is not part of another expression or of a declarator.
          Each of the following is a full expression: an initializer; the expression in an expression
          statement; the controlling expression of a selection statement (if or switch); the
          controlling expression of a while or do statement; each of the (optional) expressions of
          a for statement; the (optional) expression in a return statement. The end of a full
          expression is a sequence point.




        Note that e.g. in int foo = 1, 2, 3 the 1, 2, 3 part is a brace-enclosed list of initializers, each of which has a sequence point after it.




      • Initialization is performed in initializer list order.




        6.7.8 Initialization



        1. 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. [...]

         



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




      • However, initializer expressions are not necessarily evaluated in order.




        6.7.8 Initialization



        1. The order in which any side effects occur among the initialization list expressions is
          unspecified.




      However, that still leaves some questions unanswered:




      • Are sequence points even relevant? The basic rule is:




        6.5 Expressions



        1. Between the previous and next sequence point an object shall have its stored value
          modified at most once by the evaluation of an expression. Furthermore, the prior value
          shall be read only to determine the value to be stored.



        a[2] = 1 is an expression, but initialization is not.



        This is slightly contradicted by Annex J:




        J.2 Undefined behavior



        • Between two sequence points, an object is modified more than once, or is modified
          and the prior value is read other than to determine the value to be stored (6.5).



        Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.



      • How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?



      I think int a[5] = a[2] = 1 is executed as follows:



      1. Storage for a is allocated when its containing block is entered. The contents are indeterminate at this point.

      2. The (only) initializer is executed (a[2] = 1), followed by a sequence point. This stores 1 in a[2] and returns 1.

      3. That 1 is used to initialize a[0] (the first initializer initializes the first subobject).

      But here things get fuzzy because the remaining elements (a[1], a[2], a[3], a[4]) are supposed to be initialized to 0, but it's not clear when: Does it happen before a[2] = 1 is evaluated? If so, a[2] = 1 would "win" and overwrite a[2], but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2] should end up being 0.



      Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).






      share|improve this answer


















      • 1




        Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
        – Some programmer dude
        Sep 13 at 8:24






      • 1




        "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
        – BЈовић
        Sep 13 at 9:16






      • 2




        @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
        – melpomene
        Sep 13 at 15:52






      • 2




        @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
        – gnasher729
        Sep 13 at 22:40






      • 1




        @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
        – melpomene
        Sep 14 at 19:41














      up vote
      85
      down vote



      accepted










      TL;DR: I don't think the behavior of int a[5]=a[2]=1; is well defined, at least in C99.



      The funny part is that the only bit that makes sense to me is the part you're asking about: a[0] is set to 1 because the assignment operator returns the value that was assigned. It's everything else that's unclear.



      If the code had been int a[5] = [2] = 1 , everything would've been easy: That's a designated initializer setting a[2] to 1 and everything else to 0. But with a[2] = 1 we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.




      Here's what I've found so far:




      • a must be a local variable.




        6.7.8 Initialization



        1. All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.



        a[2] = 1 is not a constant expression, so a must have automatic storage.




      • a is in scope in its own initialization.




        6.2.1 Scopes of identifiers



        1. Structure, union, and enumeration tags have scope that begins just after the appearance of
          the tag in a type specifier that declares the tag. Each enumeration constant has scope that
          begins just after the appearance of its defining enumerator in an enumerator list. Any
          other identifier has scope that begins just after the completion of its declarator.




        The declarator is a[5], so variables are in scope in their own initialization.




      • a is alive in its own initialization.




        6.2.4 Storage durations of objects



        1. An object whose identifier is declared with no linkage and without the storage-class
          specifier static has automatic storage duration.


        2. For such an object that does not have a variable length array type, its lifetime extends
          from entry into the block with which it is associated until execution of that block ends
          in
          any way. (Entering an enclosed block or calling a function suspends, but does not end,
          execution of the current block.) If the block is entered recursively, a new instance of the
          object is created each time. The initial value of the object is indeterminate. If an
          initialization is specified for the object, it is performed each time the declaration is
          reached in the execution of the block; otherwise, the value becomes indeterminate each
          time the declaration is reached.





      • There is a sequence point after a[2]=1.




        6.8 Statements and blocks



        1. A full expression is an expression that is not part of another expression or of a declarator.
          Each of the following is a full expression: an initializer; the expression in an expression
          statement; the controlling expression of a selection statement (if or switch); the
          controlling expression of a while or do statement; each of the (optional) expressions of
          a for statement; the (optional) expression in a return statement. The end of a full
          expression is a sequence point.




        Note that e.g. in int foo = 1, 2, 3 the 1, 2, 3 part is a brace-enclosed list of initializers, each of which has a sequence point after it.




      • Initialization is performed in initializer list order.




        6.7.8 Initialization



        1. 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. [...]

         



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




      • However, initializer expressions are not necessarily evaluated in order.




        6.7.8 Initialization



        1. The order in which any side effects occur among the initialization list expressions is
          unspecified.




      However, that still leaves some questions unanswered:




      • Are sequence points even relevant? The basic rule is:




        6.5 Expressions



        1. Between the previous and next sequence point an object shall have its stored value
          modified at most once by the evaluation of an expression. Furthermore, the prior value
          shall be read only to determine the value to be stored.



        a[2] = 1 is an expression, but initialization is not.



        This is slightly contradicted by Annex J:




        J.2 Undefined behavior



        • Between two sequence points, an object is modified more than once, or is modified
          and the prior value is read other than to determine the value to be stored (6.5).



        Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.



      • How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?



      I think int a[5] = a[2] = 1 is executed as follows:



      1. Storage for a is allocated when its containing block is entered. The contents are indeterminate at this point.

      2. The (only) initializer is executed (a[2] = 1), followed by a sequence point. This stores 1 in a[2] and returns 1.

      3. That 1 is used to initialize a[0] (the first initializer initializes the first subobject).

      But here things get fuzzy because the remaining elements (a[1], a[2], a[3], a[4]) are supposed to be initialized to 0, but it's not clear when: Does it happen before a[2] = 1 is evaluated? If so, a[2] = 1 would "win" and overwrite a[2], but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2] should end up being 0.



      Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).






      share|improve this answer


















      • 1




        Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
        – Some programmer dude
        Sep 13 at 8:24






      • 1




        "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
        – BЈовић
        Sep 13 at 9:16






      • 2




        @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
        – melpomene
        Sep 13 at 15:52






      • 2




        @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
        – gnasher729
        Sep 13 at 22:40






      • 1




        @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
        – melpomene
        Sep 14 at 19:41












      up vote
      85
      down vote



      accepted







      up vote
      85
      down vote



      accepted






      TL;DR: I don't think the behavior of int a[5]=a[2]=1; is well defined, at least in C99.



      The funny part is that the only bit that makes sense to me is the part you're asking about: a[0] is set to 1 because the assignment operator returns the value that was assigned. It's everything else that's unclear.



      If the code had been int a[5] = [2] = 1 , everything would've been easy: That's a designated initializer setting a[2] to 1 and everything else to 0. But with a[2] = 1 we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.




      Here's what I've found so far:




      • a must be a local variable.




        6.7.8 Initialization



        1. All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.



        a[2] = 1 is not a constant expression, so a must have automatic storage.




      • a is in scope in its own initialization.




        6.2.1 Scopes of identifiers



        1. Structure, union, and enumeration tags have scope that begins just after the appearance of
          the tag in a type specifier that declares the tag. Each enumeration constant has scope that
          begins just after the appearance of its defining enumerator in an enumerator list. Any
          other identifier has scope that begins just after the completion of its declarator.




        The declarator is a[5], so variables are in scope in their own initialization.




      • a is alive in its own initialization.




        6.2.4 Storage durations of objects



        1. An object whose identifier is declared with no linkage and without the storage-class
          specifier static has automatic storage duration.


        2. For such an object that does not have a variable length array type, its lifetime extends
          from entry into the block with which it is associated until execution of that block ends
          in
          any way. (Entering an enclosed block or calling a function suspends, but does not end,
          execution of the current block.) If the block is entered recursively, a new instance of the
          object is created each time. The initial value of the object is indeterminate. If an
          initialization is specified for the object, it is performed each time the declaration is
          reached in the execution of the block; otherwise, the value becomes indeterminate each
          time the declaration is reached.





      • There is a sequence point after a[2]=1.




        6.8 Statements and blocks



        1. A full expression is an expression that is not part of another expression or of a declarator.
          Each of the following is a full expression: an initializer; the expression in an expression
          statement; the controlling expression of a selection statement (if or switch); the
          controlling expression of a while or do statement; each of the (optional) expressions of
          a for statement; the (optional) expression in a return statement. The end of a full
          expression is a sequence point.




        Note that e.g. in int foo = 1, 2, 3 the 1, 2, 3 part is a brace-enclosed list of initializers, each of which has a sequence point after it.




      • Initialization is performed in initializer list order.




        6.7.8 Initialization



        1. 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. [...]

         



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




      • However, initializer expressions are not necessarily evaluated in order.




        6.7.8 Initialization



        1. The order in which any side effects occur among the initialization list expressions is
          unspecified.




      However, that still leaves some questions unanswered:




      • Are sequence points even relevant? The basic rule is:




        6.5 Expressions



        1. Between the previous and next sequence point an object shall have its stored value
          modified at most once by the evaluation of an expression. Furthermore, the prior value
          shall be read only to determine the value to be stored.



        a[2] = 1 is an expression, but initialization is not.



        This is slightly contradicted by Annex J:




        J.2 Undefined behavior



        • Between two sequence points, an object is modified more than once, or is modified
          and the prior value is read other than to determine the value to be stored (6.5).



        Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.



      • How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?



      I think int a[5] = a[2] = 1 is executed as follows:



      1. Storage for a is allocated when its containing block is entered. The contents are indeterminate at this point.

      2. The (only) initializer is executed (a[2] = 1), followed by a sequence point. This stores 1 in a[2] and returns 1.

      3. That 1 is used to initialize a[0] (the first initializer initializes the first subobject).

      But here things get fuzzy because the remaining elements (a[1], a[2], a[3], a[4]) are supposed to be initialized to 0, but it's not clear when: Does it happen before a[2] = 1 is evaluated? If so, a[2] = 1 would "win" and overwrite a[2], but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2] should end up being 0.



      Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).






      share|improve this answer














      TL;DR: I don't think the behavior of int a[5]=a[2]=1; is well defined, at least in C99.



      The funny part is that the only bit that makes sense to me is the part you're asking about: a[0] is set to 1 because the assignment operator returns the value that was assigned. It's everything else that's unclear.



      If the code had been int a[5] = [2] = 1 , everything would've been easy: That's a designated initializer setting a[2] to 1 and everything else to 0. But with a[2] = 1 we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.




      Here's what I've found so far:




      • a must be a local variable.




        6.7.8 Initialization



        1. All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.



        a[2] = 1 is not a constant expression, so a must have automatic storage.




      • a is in scope in its own initialization.




        6.2.1 Scopes of identifiers



        1. Structure, union, and enumeration tags have scope that begins just after the appearance of
          the tag in a type specifier that declares the tag. Each enumeration constant has scope that
          begins just after the appearance of its defining enumerator in an enumerator list. Any
          other identifier has scope that begins just after the completion of its declarator.




        The declarator is a[5], so variables are in scope in their own initialization.




      • a is alive in its own initialization.




        6.2.4 Storage durations of objects



        1. An object whose identifier is declared with no linkage and without the storage-class
          specifier static has automatic storage duration.


        2. For such an object that does not have a variable length array type, its lifetime extends
          from entry into the block with which it is associated until execution of that block ends
          in
          any way. (Entering an enclosed block or calling a function suspends, but does not end,
          execution of the current block.) If the block is entered recursively, a new instance of the
          object is created each time. The initial value of the object is indeterminate. If an
          initialization is specified for the object, it is performed each time the declaration is
          reached in the execution of the block; otherwise, the value becomes indeterminate each
          time the declaration is reached.





      • There is a sequence point after a[2]=1.




        6.8 Statements and blocks



        1. A full expression is an expression that is not part of another expression or of a declarator.
          Each of the following is a full expression: an initializer; the expression in an expression
          statement; the controlling expression of a selection statement (if or switch); the
          controlling expression of a while or do statement; each of the (optional) expressions of
          a for statement; the (optional) expression in a return statement. The end of a full
          expression is a sequence point.




        Note that e.g. in int foo = 1, 2, 3 the 1, 2, 3 part is a brace-enclosed list of initializers, each of which has a sequence point after it.




      • Initialization is performed in initializer list order.




        6.7.8 Initialization



        1. 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. [...]

         



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




      • However, initializer expressions are not necessarily evaluated in order.




        6.7.8 Initialization



        1. The order in which any side effects occur among the initialization list expressions is
          unspecified.




      However, that still leaves some questions unanswered:




      • Are sequence points even relevant? The basic rule is:




        6.5 Expressions



        1. Between the previous and next sequence point an object shall have its stored value
          modified at most once by the evaluation of an expression. Furthermore, the prior value
          shall be read only to determine the value to be stored.



        a[2] = 1 is an expression, but initialization is not.



        This is slightly contradicted by Annex J:




        J.2 Undefined behavior



        • Between two sequence points, an object is modified more than once, or is modified
          and the prior value is read other than to determine the value to be stored (6.5).



        Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.



      • How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?



      I think int a[5] = a[2] = 1 is executed as follows:



      1. Storage for a is allocated when its containing block is entered. The contents are indeterminate at this point.

      2. The (only) initializer is executed (a[2] = 1), followed by a sequence point. This stores 1 in a[2] and returns 1.

      3. That 1 is used to initialize a[0] (the first initializer initializes the first subobject).

      But here things get fuzzy because the remaining elements (a[1], a[2], a[3], a[4]) are supposed to be initialized to 0, but it's not clear when: Does it happen before a[2] = 1 is evaluated? If so, a[2] = 1 would "win" and overwrite a[2], but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2] should end up being 0.



      Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Sep 13 at 15:56

























      answered Sep 13 at 8:03









      melpomene

      52.6k53782




      52.6k53782







      • 1




        Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
        – Some programmer dude
        Sep 13 at 8:24






      • 1




        "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
        – BЈовић
        Sep 13 at 9:16






      • 2




        @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
        – melpomene
        Sep 13 at 15:52






      • 2




        @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
        – gnasher729
        Sep 13 at 22:40






      • 1




        @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
        – melpomene
        Sep 14 at 19:41












      • 1




        Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
        – Some programmer dude
        Sep 13 at 8:24






      • 1




        "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
        – BЈовић
        Sep 13 at 9:16






      • 2




        @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
        – melpomene
        Sep 13 at 15:52






      • 2




        @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
        – gnasher729
        Sep 13 at 22:40






      • 1




        @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
        – melpomene
        Sep 14 at 19:41







      1




      1




      Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
      – Some programmer dude
      Sep 13 at 8:24




      Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
      – Some programmer dude
      Sep 13 at 8:24




      1




      1




      "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
      – BЈовић
      Sep 13 at 9:16




      "we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
      – BЈовић
      Sep 13 at 9:16




      2




      2




      @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
      – melpomene
      Sep 13 at 15:52




      @Someprogrammerdude I don't think it can be unspecified ("behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance") because the standard doesn't really provide any possibilities among which to choose. It simply doesn't say what happens, which I believe falls under "Undefined behavior is [...] indicated in this International Standard [...] by the omission of any explicit definition of behavior."
      – melpomene
      Sep 13 at 15:52




      2




      2




      @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
      – gnasher729
      Sep 13 at 22:40




      @BЈовић It's also a very nice description not only for undefined behaviour, but also for defined behaviour that needs a thread like this one to explain.
      – gnasher729
      Sep 13 at 22:40




      1




      1




      @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
      – melpomene
      Sep 14 at 19:41




      @JohnBollinger The difference is that you cannot actually initialize the a[0] subobject before evaluating its initializer, and evaluating any initializer includes a sequence point (because it's a "full expression"). Therefore I believe modifying the subobject we're initializing is fair game.
      – melpomene
      Sep 14 at 19:41












      up vote
      21
      down vote














      I don't understand, why does a[0] print 1 instead of 0?




      Presumably a[2]=1 initializes a[2] first, and the result of the expression is used to initialize a[0].



      From N2176 (C17 draft):




      6.7.9 Initialization



      1. The evaluations of the initialization list expressions are indeterminately sequenced with respect to
        one another and thus the order in which any side effects occur is unspecified. 154)



      So it would seem that output 1 0 0 0 0 would also have been possible.



      Conclusion: Don't write initializers that modifies the initialized variable on the fly.






      share|improve this answer


















      • 1




        That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
        – melpomene
        Sep 13 at 7:43










      • @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
        – user694733
        Sep 13 at 7:47






      • 1




        ... is a braced initializer list. It is not an expression.
        – melpomene
        Sep 13 at 7:49










      • @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
        – user694733
        Sep 13 at 8:03










      • @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
        – M.M
        Sep 13 at 9:01














      up vote
      21
      down vote














      I don't understand, why does a[0] print 1 instead of 0?




      Presumably a[2]=1 initializes a[2] first, and the result of the expression is used to initialize a[0].



      From N2176 (C17 draft):




      6.7.9 Initialization



      1. The evaluations of the initialization list expressions are indeterminately sequenced with respect to
        one another and thus the order in which any side effects occur is unspecified. 154)



      So it would seem that output 1 0 0 0 0 would also have been possible.



      Conclusion: Don't write initializers that modifies the initialized variable on the fly.






      share|improve this answer


















      • 1




        That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
        – melpomene
        Sep 13 at 7:43










      • @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
        – user694733
        Sep 13 at 7:47






      • 1




        ... is a braced initializer list. It is not an expression.
        – melpomene
        Sep 13 at 7:49










      • @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
        – user694733
        Sep 13 at 8:03










      • @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
        – M.M
        Sep 13 at 9:01












      up vote
      21
      down vote










      up vote
      21
      down vote










      I don't understand, why does a[0] print 1 instead of 0?




      Presumably a[2]=1 initializes a[2] first, and the result of the expression is used to initialize a[0].



      From N2176 (C17 draft):




      6.7.9 Initialization



      1. The evaluations of the initialization list expressions are indeterminately sequenced with respect to
        one another and thus the order in which any side effects occur is unspecified. 154)



      So it would seem that output 1 0 0 0 0 would also have been possible.



      Conclusion: Don't write initializers that modifies the initialized variable on the fly.






      share|improve this answer















      I don't understand, why does a[0] print 1 instead of 0?




      Presumably a[2]=1 initializes a[2] first, and the result of the expression is used to initialize a[0].



      From N2176 (C17 draft):




      6.7.9 Initialization



      1. The evaluations of the initialization list expressions are indeterminately sequenced with respect to
        one another and thus the order in which any side effects occur is unspecified. 154)



      So it would seem that output 1 0 0 0 0 would also have been possible.



      Conclusion: Don't write initializers that modifies the initialized variable on the fly.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Sep 13 at 8:17

























      answered Sep 13 at 7:28









      user694733

      10.6k12749




      10.6k12749







      • 1




        That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
        – melpomene
        Sep 13 at 7:43










      • @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
        – user694733
        Sep 13 at 7:47






      • 1




        ... is a braced initializer list. It is not an expression.
        – melpomene
        Sep 13 at 7:49










      • @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
        – user694733
        Sep 13 at 8:03










      • @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
        – M.M
        Sep 13 at 9:01












      • 1




        That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
        – melpomene
        Sep 13 at 7:43










      • @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
        – user694733
        Sep 13 at 7:47






      • 1




        ... is a braced initializer list. It is not an expression.
        – melpomene
        Sep 13 at 7:49










      • @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
        – user694733
        Sep 13 at 8:03










      • @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
        – M.M
        Sep 13 at 9:01







      1




      1




      That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
      – melpomene
      Sep 13 at 7:43




      That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
      – melpomene
      Sep 13 at 7:43












      @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
      – user694733
      Sep 13 at 7:47




      @melpomene There is the ... expression which initializes a[2] to 0, and a[2]=1 sub-expression which initializes a[2] to 1.
      – user694733
      Sep 13 at 7:47




      1




      1




      ... is a braced initializer list. It is not an expression.
      – melpomene
      Sep 13 at 7:49




      ... is a braced initializer list. It is not an expression.
      – melpomene
      Sep 13 at 7:49












      @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
      – user694733
      Sep 13 at 8:03




      @melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
      – user694733
      Sep 13 at 8:03












      @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
      – M.M
      Sep 13 at 9:01




      @melpomene there are two things to be sequenced: the first initializer, and the setting of other elements to 0
      – M.M
      Sep 13 at 9:01










      up vote
      5
      down vote













      I think the C11 standard covers this behaviour and says that the result
      is unspecified, and I don't think C18 made any relevant changes in
      this area.



      The standard language is not easy to parse.
      The relevant section of the standard is
      §6.7.9 Initialization.
      The syntax is documented as:




      initializer:

                      assignment-expression

                       initializer-list

                       initializer-list ,
      initializer-list:

                      designationopt initializer

                      initializer-list , designationopt initializer
      designation:

                      designator-list =
      designator-list:

                      designator

                      designator-list designator
      designator:

                      [ constant-expression ]

                      . identifier




      Note that one of the terms is assignment-expression, and since a[2] = 1 is indubitably an assignment expression, it is allowed inside
      initializers for arrays with non-static duration:




      §4 All the expressions in an initializer for an object that has
      static or thread storage duration shall be constant expressions or
      string literals.




      One of the key paragraphs is:




      §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.



      151) Any initializer for the subobject which is overridden
      and so not used to initialize that subobject might not be evaluated at
      all.




      And another key paragraph is:




      §23 The evaluations of the initialization list expressions are
      indeterminately sequenced with respect to one another and thus the
      order in which any side effects occur is unspecified.152)



      152) In particular, the evaluation order need not be the
      same as the order of subobject initialization.




      I'm fairly sure that paragraph §23 indicates that the notation in the
      question:



      int a[5] = a[2] = 1 ;


      leads to unspecified behaviour.
      The assignment to a[2] is a side-effect, and the evaluation order of the
      expressions are indeterminately sequenced with respect to one another.
      Consequently, I don't think there is a way to appeal to the standard and
      claim that a particular compiler is handling this correctly or incorrectly.






      share|improve this answer


























        up vote
        5
        down vote













        I think the C11 standard covers this behaviour and says that the result
        is unspecified, and I don't think C18 made any relevant changes in
        this area.



        The standard language is not easy to parse.
        The relevant section of the standard is
        §6.7.9 Initialization.
        The syntax is documented as:




        initializer:

                        assignment-expression

                         initializer-list

                         initializer-list ,
        initializer-list:

                        designationopt initializer

                        initializer-list , designationopt initializer
        designation:

                        designator-list =
        designator-list:

                        designator

                        designator-list designator
        designator:

                        [ constant-expression ]

                        . identifier




        Note that one of the terms is assignment-expression, and since a[2] = 1 is indubitably an assignment expression, it is allowed inside
        initializers for arrays with non-static duration:




        §4 All the expressions in an initializer for an object that has
        static or thread storage duration shall be constant expressions or
        string literals.




        One of the key paragraphs is:




        §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.



        151) Any initializer for the subobject which is overridden
        and so not used to initialize that subobject might not be evaluated at
        all.




        And another key paragraph is:




        §23 The evaluations of the initialization list expressions are
        indeterminately sequenced with respect to one another and thus the
        order in which any side effects occur is unspecified.152)



        152) In particular, the evaluation order need not be the
        same as the order of subobject initialization.




        I'm fairly sure that paragraph §23 indicates that the notation in the
        question:



        int a[5] = a[2] = 1 ;


        leads to unspecified behaviour.
        The assignment to a[2] is a side-effect, and the evaluation order of the
        expressions are indeterminately sequenced with respect to one another.
        Consequently, I don't think there is a way to appeal to the standard and
        claim that a particular compiler is handling this correctly or incorrectly.






        share|improve this answer
























          up vote
          5
          down vote










          up vote
          5
          down vote









          I think the C11 standard covers this behaviour and says that the result
          is unspecified, and I don't think C18 made any relevant changes in
          this area.



          The standard language is not easy to parse.
          The relevant section of the standard is
          §6.7.9 Initialization.
          The syntax is documented as:




          initializer:

                          assignment-expression

                           initializer-list

                           initializer-list ,
          initializer-list:

                          designationopt initializer

                          initializer-list , designationopt initializer
          designation:

                          designator-list =
          designator-list:

                          designator

                          designator-list designator
          designator:

                          [ constant-expression ]

                          . identifier




          Note that one of the terms is assignment-expression, and since a[2] = 1 is indubitably an assignment expression, it is allowed inside
          initializers for arrays with non-static duration:




          §4 All the expressions in an initializer for an object that has
          static or thread storage duration shall be constant expressions or
          string literals.




          One of the key paragraphs is:




          §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.



          151) Any initializer for the subobject which is overridden
          and so not used to initialize that subobject might not be evaluated at
          all.




          And another key paragraph is:




          §23 The evaluations of the initialization list expressions are
          indeterminately sequenced with respect to one another and thus the
          order in which any side effects occur is unspecified.152)



          152) In particular, the evaluation order need not be the
          same as the order of subobject initialization.




          I'm fairly sure that paragraph §23 indicates that the notation in the
          question:



          int a[5] = a[2] = 1 ;


          leads to unspecified behaviour.
          The assignment to a[2] is a side-effect, and the evaluation order of the
          expressions are indeterminately sequenced with respect to one another.
          Consequently, I don't think there is a way to appeal to the standard and
          claim that a particular compiler is handling this correctly or incorrectly.






          share|improve this answer














          I think the C11 standard covers this behaviour and says that the result
          is unspecified, and I don't think C18 made any relevant changes in
          this area.



          The standard language is not easy to parse.
          The relevant section of the standard is
          §6.7.9 Initialization.
          The syntax is documented as:




          initializer:

                          assignment-expression

                           initializer-list

                           initializer-list ,
          initializer-list:

                          designationopt initializer

                          initializer-list , designationopt initializer
          designation:

                          designator-list =
          designator-list:

                          designator

                          designator-list designator
          designator:

                          [ constant-expression ]

                          . identifier




          Note that one of the terms is assignment-expression, and since a[2] = 1 is indubitably an assignment expression, it is allowed inside
          initializers for arrays with non-static duration:




          §4 All the expressions in an initializer for an object that has
          static or thread storage duration shall be constant expressions or
          string literals.




          One of the key paragraphs is:




          §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.



          151) Any initializer for the subobject which is overridden
          and so not used to initialize that subobject might not be evaluated at
          all.




          And another key paragraph is:




          §23 The evaluations of the initialization list expressions are
          indeterminately sequenced with respect to one another and thus the
          order in which any side effects occur is unspecified.152)



          152) In particular, the evaluation order need not be the
          same as the order of subobject initialization.




          I'm fairly sure that paragraph §23 indicates that the notation in the
          question:



          int a[5] = a[2] = 1 ;


          leads to unspecified behaviour.
          The assignment to a[2] is a side-effect, and the evaluation order of the
          expressions are indeterminately sequenced with respect to one another.
          Consequently, I don't think there is a way to appeal to the standard and
          claim that a particular compiler is handling this correctly or incorrectly.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Sep 23 at 13:57

























          answered Sep 16 at 6:48









          Jonathan Leffler

          547k856491001




          547k856491001




















              up vote
              3
              down vote













              My Understanding is
              a[2]=1 returns value 1 so code becomes



              int a[5]=a[2]=1 --> int a[5]=1


              int a[5]=1 assign value for a[0]=1



              Hence it print 1 for a[0]



              For example



              char str[10]=‘H’,‘a’,‘i’;


              char str[0] = ‘H’;
              char str[1] = ‘a’;
              char str[2] = ‘i;





              share|improve this answer
















              • 1




                This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                – Kami Kaze
                Sep 14 at 8:20











              • I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
                – Karthika
                Sep 14 at 9:56










              • You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
                – Kami Kaze
                Sep 14 at 10:00










              • But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
                – Karthika
                Sep 14 at 10:23











              • OP asked "Is it undefined behaviour?". Your answer doesn't say.
                – melpomene
                Sep 14 at 12:12














              up vote
              3
              down vote













              My Understanding is
              a[2]=1 returns value 1 so code becomes



              int a[5]=a[2]=1 --> int a[5]=1


              int a[5]=1 assign value for a[0]=1



              Hence it print 1 for a[0]



              For example



              char str[10]=‘H’,‘a’,‘i’;


              char str[0] = ‘H’;
              char str[1] = ‘a’;
              char str[2] = ‘i;





              share|improve this answer
















              • 1




                This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                – Kami Kaze
                Sep 14 at 8:20











              • I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
                – Karthika
                Sep 14 at 9:56










              • You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
                – Kami Kaze
                Sep 14 at 10:00










              • But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
                – Karthika
                Sep 14 at 10:23











              • OP asked "Is it undefined behaviour?". Your answer doesn't say.
                – melpomene
                Sep 14 at 12:12












              up vote
              3
              down vote










              up vote
              3
              down vote









              My Understanding is
              a[2]=1 returns value 1 so code becomes



              int a[5]=a[2]=1 --> int a[5]=1


              int a[5]=1 assign value for a[0]=1



              Hence it print 1 for a[0]



              For example



              char str[10]=‘H’,‘a’,‘i’;


              char str[0] = ‘H’;
              char str[1] = ‘a’;
              char str[2] = ‘i;





              share|improve this answer












              My Understanding is
              a[2]=1 returns value 1 so code becomes



              int a[5]=a[2]=1 --> int a[5]=1


              int a[5]=1 assign value for a[0]=1



              Hence it print 1 for a[0]



              For example



              char str[10]=‘H’,‘a’,‘i’;


              char str[0] = ‘H’;
              char str[1] = ‘a’;
              char str[2] = ‘i;






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Sep 13 at 9:43









              Karthika

              786




              786







              • 1




                This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                – Kami Kaze
                Sep 14 at 8:20











              • I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
                – Karthika
                Sep 14 at 9:56










              • You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
                – Kami Kaze
                Sep 14 at 10:00










              • But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
                – Karthika
                Sep 14 at 10:23











              • OP asked "Is it undefined behaviour?". Your answer doesn't say.
                – melpomene
                Sep 14 at 12:12












              • 1




                This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                – Kami Kaze
                Sep 14 at 8:20











              • I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
                – Karthika
                Sep 14 at 9:56










              • You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
                – Kami Kaze
                Sep 14 at 10:00










              • But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
                – Karthika
                Sep 14 at 10:23











              • OP asked "Is it undefined behaviour?". Your answer doesn't say.
                – melpomene
                Sep 14 at 12:12







              1




              1




              This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
              – Kami Kaze
              Sep 14 at 8:20





              This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
              – Kami Kaze
              Sep 14 at 8:20













              I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
              – Karthika
              Sep 14 at 9:56




              I have a doubt.Is the concept I posted wrong?Could you clarify me with this?
              – Karthika
              Sep 14 at 9:56












              You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
              – Kami Kaze
              Sep 14 at 10:00




              You just speculate for reasons, while there is a very good answer already given with relevant parts of the standard. Just saying how it could happen is not what the the question is about. It is about what the standard says should happen.
              – Kami Kaze
              Sep 14 at 10:00












              But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
              – Karthika
              Sep 14 at 10:23





              But the person who posted above question asked the reason and why does it happen? So only i dropped this answer.But concept is correct.Right?
              – Karthika
              Sep 14 at 10:23













              OP asked "Is it undefined behaviour?". Your answer doesn't say.
              – melpomene
              Sep 14 at 12:12




              OP asked "Is it undefined behaviour?". Your answer doesn't say.
              – melpomene
              Sep 14 at 12:12










              up vote
              1
              down vote













              I try to give a short and simple answer for the puzzle: int a[5] = a[2] = 1 ;



              1. First a[2] = 1 is set. That means the array says: 0 0 1 0 0

              2. But behold, given that you did it in the brackets, which are used to initialize the array in order, it takes the first value (which is 1) and sets that to a[0]. It is as if int a[5] = a[2] ; would remain, where we already got a[2] = 1. The resulting array is now: 1 0 1 0 0

              Another example: int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ; - Even though the order is somewhat arbitrary, assuming it goes from left to right, it would go in these 6 steps:



              0 0 0 1 0 0
              1 0 0 1 0 0
              1 0 0 1 2 0
              1 2 0 1 2 0
              1 2 0 1 2 3
              1 2 3 1 2 3





              share|improve this answer


















              • 1




                A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
                – melpomene
                Sep 13 at 15:48






              • 1




                "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
                – melpomene
                Sep 14 at 12:14






              • 1




                "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
                – melpomene
                Sep 14 at 14:49






              • 1




                The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
                – John Bollinger
                Sep 14 at 15:02







              • 1




                "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
                – Jeroen Mostert
                Sep 14 at 16:04














              up vote
              1
              down vote













              I try to give a short and simple answer for the puzzle: int a[5] = a[2] = 1 ;



              1. First a[2] = 1 is set. That means the array says: 0 0 1 0 0

              2. But behold, given that you did it in the brackets, which are used to initialize the array in order, it takes the first value (which is 1) and sets that to a[0]. It is as if int a[5] = a[2] ; would remain, where we already got a[2] = 1. The resulting array is now: 1 0 1 0 0

              Another example: int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ; - Even though the order is somewhat arbitrary, assuming it goes from left to right, it would go in these 6 steps:



              0 0 0 1 0 0
              1 0 0 1 0 0
              1 0 0 1 2 0
              1 2 0 1 2 0
              1 2 0 1 2 3
              1 2 3 1 2 3





              share|improve this answer


















              • 1




                A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
                – melpomene
                Sep 13 at 15:48






              • 1




                "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
                – melpomene
                Sep 14 at 12:14






              • 1




                "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
                – melpomene
                Sep 14 at 14:49






              • 1




                The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
                – John Bollinger
                Sep 14 at 15:02







              • 1




                "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
                – Jeroen Mostert
                Sep 14 at 16:04












              up vote
              1
              down vote










              up vote
              1
              down vote









              I try to give a short and simple answer for the puzzle: int a[5] = a[2] = 1 ;



              1. First a[2] = 1 is set. That means the array says: 0 0 1 0 0

              2. But behold, given that you did it in the brackets, which are used to initialize the array in order, it takes the first value (which is 1) and sets that to a[0]. It is as if int a[5] = a[2] ; would remain, where we already got a[2] = 1. The resulting array is now: 1 0 1 0 0

              Another example: int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ; - Even though the order is somewhat arbitrary, assuming it goes from left to right, it would go in these 6 steps:



              0 0 0 1 0 0
              1 0 0 1 0 0
              1 0 0 1 2 0
              1 2 0 1 2 0
              1 2 0 1 2 3
              1 2 3 1 2 3





              share|improve this answer














              I try to give a short and simple answer for the puzzle: int a[5] = a[2] = 1 ;



              1. First a[2] = 1 is set. That means the array says: 0 0 1 0 0

              2. But behold, given that you did it in the brackets, which are used to initialize the array in order, it takes the first value (which is 1) and sets that to a[0]. It is as if int a[5] = a[2] ; would remain, where we already got a[2] = 1. The resulting array is now: 1 0 1 0 0

              Another example: int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ; - Even though the order is somewhat arbitrary, assuming it goes from left to right, it would go in these 6 steps:



              0 0 0 1 0 0
              1 0 0 1 0 0
              1 0 0 1 2 0
              1 2 0 1 2 0
              1 2 0 1 2 3
              1 2 3 1 2 3






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Sep 14 at 13:58

























              answered Sep 13 at 11:58









              Battle

              31717




              31717







              • 1




                A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
                – melpomene
                Sep 13 at 15:48






              • 1




                "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
                – melpomene
                Sep 14 at 12:14






              • 1




                "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
                – melpomene
                Sep 14 at 14:49






              • 1




                The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
                – John Bollinger
                Sep 14 at 15:02







              • 1




                "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
                – Jeroen Mostert
                Sep 14 at 16:04












              • 1




                A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
                – melpomene
                Sep 13 at 15:48






              • 1




                "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
                – melpomene
                Sep 14 at 12:14






              • 1




                "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
                – melpomene
                Sep 14 at 14:49






              • 1




                The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
                – John Bollinger
                Sep 14 at 15:02







              • 1




                "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
                – Jeroen Mostert
                Sep 14 at 16:04







              1




              1




              A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
              – melpomene
              Sep 13 at 15:48




              A = B = C = 5 is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5)) because the = operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
              – melpomene
              Sep 13 at 15:48




              1




              1




              "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
              – melpomene
              Sep 14 at 12:14




              "It goes from left to right, each starting with the internal declaration" is incorrect. The C standard explicitly says "The order in which any side effects occur among the initialization list expressions is unspecified."
              – melpomene
              Sep 14 at 12:14




              1




              1




              "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
              – melpomene
              Sep 14 at 14:49




              "You test the code from my example sufficient times and see if the results are consistent." That's not how it works. You don't seem to understand what undefined behavior is. Everything in C has undefined behavior by default; it's just that some parts have behavior that is defined by the standard. To prove that something has defined behavior, you must cite the standard and show where it defines what should happen. In the absence of such a definition, the behavior is undefined.
              – melpomene
              Sep 14 at 14:49




              1




              1




              The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
              – John Bollinger
              Sep 14 at 15:02





              The assertion in point (1) is an enormous leap over the key question here: does the implicit initialization of element a[2] to 0 occur before the side effect of the a[2] = 1 initializer expression is applied? The observed result is as if it was, but the standard does not appear to specify that that should be the case. That is the center of the controversy, and this answer completely overlooks it.
              – John Bollinger
              Sep 14 at 15:02





              1




              1




              "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
              – Jeroen Mostert
              Sep 14 at 16:04




              "Undefined behavior" is a technical term with a narrow meaning. It doesn't mean "behavior we're not really sure about". The key insight here is that no test, with no compiler, can ever show a particular program is or is not well-behaved according to the standard, because if a program has undefined behavior, the compiler is allowed to do anything -- including working in a perfectly predictable and reasonable manner. It's not simply a quality of implementation issue where the compiler writers document things -- that's unspecified or implementation-defined behavior.
              – Jeroen Mostert
              Sep 14 at 16:04










              up vote
              0
              down vote













              The assignment a[2]= 1 is an expression that has the value 1, and you essentially wrote int a[5]= 1 ; (with the side effect that a[2] is assigned 1 as well).






              share|improve this answer
























                up vote
                0
                down vote













                The assignment a[2]= 1 is an expression that has the value 1, and you essentially wrote int a[5]= 1 ; (with the side effect that a[2] is assigned 1 as well).






                share|improve this answer






















                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  The assignment a[2]= 1 is an expression that has the value 1, and you essentially wrote int a[5]= 1 ; (with the side effect that a[2] is assigned 1 as well).






                  share|improve this answer












                  The assignment a[2]= 1 is an expression that has the value 1, and you essentially wrote int a[5]= 1 ; (with the side effect that a[2] is assigned 1 as well).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 19 at 7:05









                  Yves Daoust

                  35.4k62557




                  35.4k62557




















                      up vote
                      -3
                      down vote













                      Order of operations.



                      First, the assignment occurs and the assignment is evaluated as this:



                      int a[5] = 1, which yields the following:



                      1, 0, 0, 0, 0. We get 1 because a[2]=1 evaluates to true and is implicitly cast to 1 in the assignment series.



                      Second, the expression within the curly brackets is executed, which results in actually assigning 1 to the array at index 2.



                      You can experiment by compiling int a[5]=true; and also int a[5]=a[3]=3; and observing the results.



                      edit: I was wrong about the result of the assignment within the initialization list, that results in an integer that is the same as what was assigned.






                      share|improve this answer






















                      • This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                        – Kami Kaze
                        Sep 14 at 8:19







                      • 1




                        "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                        – melpomene
                        Sep 14 at 12:10














                      up vote
                      -3
                      down vote













                      Order of operations.



                      First, the assignment occurs and the assignment is evaluated as this:



                      int a[5] = 1, which yields the following:



                      1, 0, 0, 0, 0. We get 1 because a[2]=1 evaluates to true and is implicitly cast to 1 in the assignment series.



                      Second, the expression within the curly brackets is executed, which results in actually assigning 1 to the array at index 2.



                      You can experiment by compiling int a[5]=true; and also int a[5]=a[3]=3; and observing the results.



                      edit: I was wrong about the result of the assignment within the initialization list, that results in an integer that is the same as what was assigned.






                      share|improve this answer






















                      • This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                        – Kami Kaze
                        Sep 14 at 8:19







                      • 1




                        "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                        – melpomene
                        Sep 14 at 12:10












                      up vote
                      -3
                      down vote










                      up vote
                      -3
                      down vote









                      Order of operations.



                      First, the assignment occurs and the assignment is evaluated as this:



                      int a[5] = 1, which yields the following:



                      1, 0, 0, 0, 0. We get 1 because a[2]=1 evaluates to true and is implicitly cast to 1 in the assignment series.



                      Second, the expression within the curly brackets is executed, which results in actually assigning 1 to the array at index 2.



                      You can experiment by compiling int a[5]=true; and also int a[5]=a[3]=3; and observing the results.



                      edit: I was wrong about the result of the assignment within the initialization list, that results in an integer that is the same as what was assigned.






                      share|improve this answer














                      Order of operations.



                      First, the assignment occurs and the assignment is evaluated as this:



                      int a[5] = 1, which yields the following:



                      1, 0, 0, 0, 0. We get 1 because a[2]=1 evaluates to true and is implicitly cast to 1 in the assignment series.



                      Second, the expression within the curly brackets is executed, which results in actually assigning 1 to the array at index 2.



                      You can experiment by compiling int a[5]=true; and also int a[5]=a[3]=3; and observing the results.



                      edit: I was wrong about the result of the assignment within the initialization list, that results in an integer that is the same as what was assigned.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Sep 14 at 14:40

























                      answered Sep 13 at 23:01









                      Brandon Mantzey

                      11512




                      11512











                      • This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                        – Kami Kaze
                        Sep 14 at 8:19







                      • 1




                        "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                        – melpomene
                        Sep 14 at 12:10
















                      • This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                        – Kami Kaze
                        Sep 14 at 8:19







                      • 1




                        "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                        – melpomene
                        Sep 14 at 12:10















                      This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                      – Kami Kaze
                      Sep 14 at 8:19





                      This is a [language-lawyer] question, but this is not an answer that works with the standard, thus making it irrelevant. Plus there are also 2 much more in-depth answers available and your answer does not seem to add anything.
                      – Kami Kaze
                      Sep 14 at 8:19





                      1




                      1




                      "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                      – melpomene
                      Sep 14 at 12:10




                      "a[2]=1 evaluates to true and is implicitly cast to 1" is nonsense. a[2] = 1 evaluates to 1, there is no cast, and there is no assignment series. You claim that a[2]=1 is evaluated first, and then the expression in curly brackets is executed, which is also a[2]=1. That makes no sense.
                      – melpomene
                      Sep 14 at 12:10

















                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52307474%2fconfusion-about-array-initialization-in-c%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay