20

I have doubt regarding the following piece of code :

int main()
{
    int array1 = {1,2,3,4,5}; //error in c++ , warning in c
    int array2[] = {1,2,3,4,5};
    int array3[5] = {1,2,3,4,5};
}

This piece of code gives a error on line 3 in c++ but not in c?

I know array1 is actually an int and array2 and array3 are arrays, so why doesn't a c compiler show a error , but just a warning: "excess elements in scalar initialization"

Is there a use of such a definition and why is it valid in c?

9
  • 2
    which compiler are you using as VS 2012 treat it as error Commented Oct 29, 2014 at 10:25
  • 21
    C is not the same as C++. Commented Oct 29, 2014 at 10:26
  • 2
    Which line exactly gives the error? Line 4 is the declaration of array2, but the only problematic line is that of array1. Commented Oct 29, 2014 at 10:27
  • 1
    S(he) should say what s(he) means. Commented Oct 29, 2014 at 11:18
  • 2
    @BasileStarynkevitch In this case, they are. Almost word for word. Commented Oct 29, 2014 at 11:56

7 Answers 7

25

It is not valid C. See C11 6.7.9:

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

I would guess that you are using gcc. Then if you want your program to behave as strict standard C, compile it as such:

gcc -std=c11 -pedantic-errors

gives

error: excess elements in scalar initializer

Sign up to request clarification or add additional context in comments.

2 Comments

It's a constraint violation and gcc correctly issues a diagnostic as required even without -pedantic-errors, which strict enough as far as ISO C is concerned. An implementation is not required to reject the code.
@BlueMoon That's because there is no such things as warnings and errors in the standard. For the programmer, errors are better.
15

It isn't valid in C. It just has less checks on the code. This is Undefined behaviour.

From: C11 draft N1570; 6.7.9 Initialisation

Constraints
2 No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
3 The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.

Definitely breaks constraint 2. Is an int a complete object type?

from Annex J.2 (undefined behaviour):

The initializer for a scalar is neither a single expression nor a single expression enclosed in braces (6.7.9).

extra:
@James Kanze:

prog.c:4:12: error: expected identifier or ‘(’ before numeric constant
  int i = 1,2,3,4,5;
            ^

you can do it, but you need to make it one expression:

int i = (1,2,3,4,5); //need parenthesis, evaluates to 5, values 1-4 thrown away.

Compiling with an int initialised with an initalizer-list spawns a warning (in gcc):

prog.c:5:2: warning: excess elements in scalar initializer [enabled by default]
  int j = {1,2,3,4,5};
  ^

but it appears that the compiler is smart enough to only initialise the int and not the following memory. demo

4 Comments

Not sure a constraint violation leads to undefined behaviour. Does the C standard state or imply that?
But 1, 2, 3, 4, 5 can be interpreted as a single initializer. (int x = 1, 2, 3, 4, 5; is definitely legal.)
but {1,2,3,4,5} != 1,2,3,4,5. The former is an initialiser-list, and the latter is 5 different values with the comma operator. I think this applies: The initializer for a scalar is neither a single expression nor a single expression enclosed in braces (6.7.9). Please correct me if wrong
@JamesKanze added comparison between int i = {12345}; and int j = (1,2,3,4,5);
11

It's valid as per the C specification.

Quote from C11 section 6.7.9 (Initialization):

Syntax

1 initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }

So an initializer can either be a direct expression (assignment-expression above), or a brace-enclose list of initializers. The constraints in that section of the standard does not limit this for "normal" (non-array or non-pointer) variables.

That allows you to write e.g.

int a = { 1 };

6 Comments

This is the most pertinent (and even correct) answer from this list of answers.
My C compiler does accept the single value {1} but says of OP's array1 "error C2078: too many initializers".
But what about the very first normative text below the mentioned syntax? No initializer shall attempt to provide a value for an object not contained within the entity being initialized. The syntax you cite indeed allows int a = {1} but that doesn't mean that int array1 = {1,2,3,4,5}; is allowed, for the same reason it doesn't allow int array1[1] = {1,2,3,4,5};
Actually, there's no difference between C and C++ here. In both cases, there is an ambiguity in the standard, and the reason the OP's C and C++ compilers behave differently is simply because the authors interpreted the standard differently.
Citing the grammar without the constraints really does not tell enough of the story, this is really only half the answer, the constraints in the text are important to this question.
|
3

Like everyone else, I assume that the line you're wondering about is:

int array1 = {1,2,3,4,5};

In this case, there is no difference between C and C++; the line is arguably legal in both languages, but it doesn't mean what you might think. In both C and C++, there is a statement to the effect that if the type is a scalar type (int is), then the contents of the {...} must be a single expression. And 1,2,3,4,5 can be interpreted as a single expression (with the comma operator); something like:

int array1 = 1, 2, 3, 4, 5;

is clearly legal.

It's somewhat ambiguous, however, since in both languages, the grammar for this type of initialization makes the , punctuation, and not an operator. So it is a question of interpretation; is the statement that the contents must be a single expression a constraint on the grammar (which would cause the comma to become an operator), or a constraint on the results of evaluating the specified grammar. My intuitive feeling is that the second is the intent, and that the statement should result in an error. But the difference isn't between C and C++, but between the way the authors of the compilers are interpreting the standard.

EDIT:

On rereading a little closer: in the C++ standard, it explicitly says that

If T is a scalar type, then a declaration of the form

    T x = { a };

is equivalent to

    T x = a;

Which doesn't leave much wriggle room: in C++, the statement seems clearly legal; it's only in C where there is some ambiguity.

4 Comments

I don't believe there is an ambiguity here, the grammar simply does not allow for the , to be a comma operator. If we look at 6.7.8 the grammar for initialzer includes assignment-expression which can not get us to a comma operator without () ... so we can do {(1,2,3,4,5)} but that has dubious usefulness.
@ShafikYaghmour That's a good point. But that would seem to mean that int a = 1, 2, 3; is illegal as well. I'm pretty sure that I've used it (or something similar), though. Or maybe I've always enclosed it in parentheses; I'm not sure. (I'd use the parentheses to make it clear to the reader that only one expression was involved.)
gcc -std=c99 -pedantic=errors refuses to compile int a = 1, 2;. Your suggested reading of the standard would also cause problems with, for example, int a = 1, b = 2; at block-scope when a file-scope declaration of b is visible or with the GCC extension of statement expressions (the GCC extensions are intended to not conflict with ISO C).
@mafso Yes. I think you're right; I probably had the extra parentheses in there.
2

The right way to initialize an array in C/C++ is:

int array2[] = {1,2,3,4,5};

Here the square brackets actually inform the compiler that this is an array, a set of numbers in your case. In that way of initialization it is not necessary to specify the length of the array. The compiler will know.

The second way is to define an array and post initialize it:

int array3[5];
int *array = new int[5];

In this case you'll need to inform the compiler what size the array will be. Moreover, in the second case you need to delete the memory manually.

1 Comment

That's not an answer to the question.
2

As your compiler says, this is not correct for C, either. The important thing to notice here is that in case of such "constraint violations" (the official term) the compiler may just produce a diagnostic (which your compiler did) and continue.

That is why generally you should ensure that your code compiles without any diagnostic whatsoever.

Comments

1

C is a low-level permissive language. It allows to affect a pointer to an int.

int array1 = {1,2,3,4,5};

EDIT :

I should have tested it under different compilers before writing stupid things.

This is rejected as error by MSVC (2008).

Both gcc and clang issue a warning excess elements in scalar initializer and simply affect 1 to a.

2 Comments

How does compiler know it's an array of chars? Why not integers? doubles anyone? Sorry, but your answer is nonsense. Initializer list does not have type in C.
You could do some nasty reinterpret casting to make the pointer an int, although I suspect not on initialization. +1 for making a false statement and then learning from it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.