Каково поведение, когда инициализаторов больше, чем размер массива?

Я хотел бы знать, что происходит, когда инициализаторов больше, чем размер массива, например. :

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

Конечно, мой компилятор предупреждает об этом. Я ожидал неопределенного поведения, но не нашел в стандарте C11 ни одного пункта об этом. Итак, я что-то пропустил?


person md5    schedule 29.08.2012    source источник
comment
Что это за компилятор? Это ошибки на VS2010.   -  person Mysticial    schedule 29.08.2012
comment
Это даже не должно компилироваться: ideone.com/gWs4i   -  person Nawaz    schedule 29.08.2012
comment
gcc 4.4.5, -Wall -Wextra -pedantic, выводит только предупреждение.   -  person md5    schedule 29.08.2012
comment
Второй абзац в 6.7.9 C11 гласит: Ни один инициализатор не должен пытаться предоставить значение для объекта, не содержащегося в инициализируемом объекте. Я думаю, что это запрещает иметь больше инициализаторов, чем элементов массива.   -  person cnicutar    schedule 29.08.2012
comment
Почему вы ожидаете неопределенного поведения для ошибки, которую компилятор может легко обнаружить?   -  person Jim Balter    schedule 30.08.2012
comment
@Jim Balter: Иногда мой компилятор предупреждает, даже если нет неправильного поведения (например, переменная не используется).   -  person md5    schedule 30.08.2012
comment
Это не относится к моему вопросу.   -  person Jim Balter    schedule 30.08.2012
comment
@JimBalter Учитывая, что компиляция исходного файла, который не заканчивается символом новой строки, или файла, в котором строковый литерал не заканчивается в конце строки, является неопределенным поведением, я считаю этот вопрос вполне законным независимо от того, что принимают компиляторы. .   -  person Pascal Cuoq    schedule 02.09.2012
comment
@PascalCuoq Я понятия не имею, о каком вопросе вы говорите, который кто-то назвал незаконным. Я задал вопрос об ожидании. Несвязанные случаи, на которые вы ссылаетесь, на самом деле имеют причины, которые не имеют ничего общего со способностью компилятора их обнаруживать, а скорее допускают определенные виды реализаций, которые были известны комитету по стандартам.   -  person Jim Balter    schedule 04.09.2012
comment
@JimBalter OP спрашивает, является ли что-то UB. Вы комментируете, риторически спрашивая, почему это должно быть, поскольку это легко обнаружить. Я указываю, что некоторые легко обнаруживаемые шаблоны являются UB, хотя они легко могут быть сделаны синтаксическими ошибками. Это делает вопрос ОП законным ИМХО (ваш риторический вопрос подразумевает, что это не так). «Несвязанные случаи», о которых я упоминаю, связаны в силу того, что их легко обнаружить и UB. У комитета по стандартам были свои причины, но, поскольку ОП не было во время обсуждения, он может законно спросить, является ли другой легко обнаруживаемый шаблон UB.   -  person Pascal Cuoq    schedule 04.09.2012
comment
@PascalCuoq Мой вопрос не был риторическим, и я никогда не говорил, что любой вопрос ОП неправомерен. Опять же, я говорил об ожиданиях ОП. Наслаждайтесь дебатами с соломенным человеком, но я ухожу.   -  person Jim Balter    schedule 04.09.2012


Ответы (3)


Код плохо сформирован как на C, так и на C++.

С++ 11 §8.5.1 [dcl.init.aggr]/6 гласит:

список-инициализаторов имеет неправильный формат, если количество предложений-инициализаторов превышает количество членов или элементов для инициализации.

C11 §6.7.9/2 гласит:

Ни один инициализатор не должен пытаться предоставить значение для объекта, не содержащегося в инициализируемом объекте.

person James McNellis    schedule 29.08.2012

Я взглянул на ассемблерный gcc, созданный для вашего примера, и похоже, что он идет по «безопасному» маршруту; он просто не загружает значения, превышающие размер массива:

void main() {
    int t[3] = { 1, 2, 3, 4 };
}

Генерирует следующую сборку:

main:
    pushl %ebp
    movl  %esp, %ebp
    subl  $16, %esp
    movl  $1, -12(%ebp)
    movl  $2, -8(%ebp)
    movl  $3, -4(%ebp)
    leave
    ret

Это было создано с помощью gcc 4.4.3.

person Ethan Brown    schedule 29.08.2012
comment
Для компилятора выделять три элемента, но сохранять четыре было бы не просто небезопасно, это было бы порочно, изо всех сил стараясь наказать программиста за предоставление слишком большого количества инициализаторов. - person Jim Balter; 30.08.2012

Ну, это зависит от вашего компилятора. Некоторые даже не позволят вам построить с этим, Visual Express дает:

error C2078: too many initializers

В то время как gcc позволяет ему летать, но предупреждает вас, что слишком много элементов... Я не думаю, что в этом случае есть ожидаемое поведение, поскольку оно не определено, но это точно не сработает.

Ex:

int t[3] = { 1, 2, 3, 4 }; 
int i;

for(i = 0; i< 5; i++){
    printf("val = %d\n", t[i]);}

val = 1
val = 2
val = 3
val = 4
val = 134513760

Я не занимался дизассемблированием, но я почти уверен, что в конце он просто сталкивается с другими данными.

person Mike    schedule 29.08.2012
comment
Ну, учитывая, что i[4] даже не определен в инициализаторе, я не особо удивлен? тот факт, что он правильно выводит i[3], удивителен сам по себе, но этого не следует ожидать, поскольку он не определен. - person ardent; 29.08.2012
comment
Да, я думаю, это был удачный пробег. - person Mike; 29.08.2012