0

有人可以告诉我这样的构造在 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    $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

4 回答 4

4

本身array[argc += 7]是可以的,结果argc + 7将用作array.

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

于 2019-01-15T13:10:31.020 回答
4

如果a[i+=N]表达式i += N总是在访问索引之前首先被评估。但是您提供的示例调用了 UB,因为您的示例数组仅包含两个元素,因此您正在访问数组的范围之外。

于 2019-01-15T13:08:18.587 回答
2

您的情况显然是未定义的行为,因为您将超出数组范围,原因如下:

首先,表达式array[argc += 7]等于*((array)+(argc+=7)),并且操作数的值将在被评估之前+被评估(参见此处);运算符+=是一个赋值(而不是副作用),赋值的值是赋值后argc(在这种情况下)的结果(参见此处)。因此,+=7下标生效;

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

因此,UB。

于 2019-01-15T13:14:16.253 回答
1

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

于 2019-01-15T13:06:37.627 回答