在数组索引中将变量递增 N

Increment variable by N inside array index

有人能告诉我这样的构造在 C++ 中是否有效(即不是 UB)。因此我有一些段错误,花了几天时间试图弄清楚那里发生了什么。

// 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    , %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    , %rsp
    .cfi_def_cfa_offset 32
    movq    %fs:40, %rax
    movq    %rax, 8(%rsp)
    xorl    %eax, %eax
    movabsq 5201762403, %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

那么,我可以假设这样的行为是标准行为吗?

这是正常行为。数组的名称实际上是指向数组第一个元素的指针。 array[n] 与 *(array+n)

相同

a[i+=N] 的情况下,表达式 i += N 将始终在访问索引之前先求值。但是您提供的示例调用 UB,因为您的示例数组仅包含两个元素,因此您正在访问数组的边界。

本身array[argc += 7]就可以,argc + 7的结果将用作array的索引。

但是,在您的示例中,array 只有 2 个元素,并且 argc 永远不会为负,因此您的代码将始终由于数组访问越界而导致 UB。

您的情况显然是未定义的行为,因为您将出于以下原因超出数组界限:

首先,表达式 array[argc += 7] 等于 *((array)+(argc+=7)),操作数的值将在计算 + 之前计算(参见 here); Operator += is an assignment (and not a side effect), and the value of an assignment is the result of argc (in this case) after the assignment (cf. here)。因此,+=7 对下标有效;

其次,argc在C++中被定义为永不为负(参见here);所以 argc += 7 将永远是 >=7 (或者在非常不现实的场景中有符号整数溢出,但仍然是 UB)。

因此,UB。