Инкремент переменной на N внутри индекса массива

Может ли кто-нибудь сказать мне, действительно ли такая конструкция допустима (то есть не UB) в C++. Из-за этого у меня есть некоторые ошибки, и я провел пару дней, пытаясь выяснить, что там происходит.

// Synthetic example  
int main(int argc, char** argv)
{
    int array[2] = {99, 99};
    /*
      The point is here. Is it legal? Does it have defined behaviour? 
      Will it increment first and than access element or vise versa? 
    */
    std::cout << array[argc += 7]; // Use argc just to avoid some optimisations
}

Поэтому, конечно, я провел некоторый анализ, и GCC(5/7), и clang(3.8) генерируют один и тот же код. Сначала добавь, чем получи доступ.

Clang(3.8):  clang++ -O3 -S test.cpp

    leal    7(%rdi), %ebx
    movl    .L_ZZ4mainE5array+28(,%rax,4), %esi
    movl    $_ZSt4cout, %edi
    callq   _ZNSolsEi
    movl    $.L.str, %esi
    movl    $1, %edx
    movq    %rax, %rdi
    callq   _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l

GCC(5/7) g++-7 -O3 -S test.cpp

    leal    7(%rdi), %ebx
    movl    $_ZSt4cout, %edi
    subq    $16, %rsp
    .cfi_def_cfa_offset 32
    movq    %fs:40, %rax
    movq    %rax, 8(%rsp)
    xorl    %eax, %eax
    movabsq $425201762403, %rax
    movq    %rax, (%rsp)
    movslq  %ebx, %rax
    movl    (%rsp,%rax,4), %esi
    call    _ZNSolsEi
    movl    $.LC0, %esi
    movq    %rax, %rdi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    movl    %ebx, %esi

Итак, могу ли я предположить, что такое поведение является стандартным?

4 ответа

Решение

Само собой array[argc += 7] все в порядке, результат argc + 7 будет использоваться в качестве индекса array,

Однако в вашем примере array имеет только 2 элемента, и argc никогда не бывает отрицательным, поэтому ваш код всегда будет приводить к UB из-за доступа к массиву вне границ.

В случае a[i+=N] выражение i += N всегда будет оцениваться в первую очередь, прежде чем получить доступ к индексу. Но приведенный вами пример вызывает UB, поскольку ваш примерный массив содержит только два элемента, и, таким образом, вы получаете доступ за пределы массива.

В вашем случае поведение явно не определено, поскольку вы превысите границы массива по следующим причинам:

Во-первых, выражение array[argc += 7] равно *((array)+(argc+=7))и значения операндов будут оцениваться до + оценивается (см. здесь); оператор += является назначением (а не побочным эффектом), а значение присвоения является результатом argc (в этом случае) после назначения (см. здесь). Следовательно +=7 становится эффективным для подписки;

Во-вторых, argc определяется в C++, чтобы никогда не быть отрицательным (см. здесь); Так argc += 7 всегда будет >=7 (или целочисленное переполнение со знаком в очень нереальном сценарии, но все же UB).

Следовательно, UB.

Это нормальное поведение. Имя массива фактически является указателем на первый элемент массива. И массив [n] такой же, как *(массив +n)

Другие вопросы по тегам