在数组索引中按N递增变量 有人能告诉我,这种结构是否有效,即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 }

在数组索引中按N递增变量 有人能告诉我,这种结构是否有效,即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 },c++,c++11,gcc,gcc7,C++,C++11,Gcc,Gcc7,那么,我能假设这样的一个baheviour是标准的吗?这是正常的行为。数组的名称实际上是指向数组第一个元素的指针。数组[n]与*array+n相同如果是[i+=n],则在访问索引之前,始终首先计算表达式i+=n。但是您提供的示例调用UB,因为您的示例数组只包含两个元素,因此您正在访问数组的边界之外。数组本身[argc+=7]是可以的,argc+7的结果将用作数组的索引 但是,在您的示例中,数组只有2个元素,并且argc从来都不是负的,因此您的代码总是会由于超出边界的数组访问而导致UB。您的情况显

那么,我能假设这样的一个baheviour是标准的吗?

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

如果是[i+=n],则在访问索引之前,始终首先计算表达式i+=n。但是您提供的示例调用UB,因为您的示例数组只包含两个元素,因此您正在访问数组的边界之外。

数组本身[argc+=7]是可以的,argc+7的结果将用作数组的索引


但是,在您的示例中,数组只有2个元素,并且argc从来都不是负的,因此您的代码总是会由于超出边界的数组访问而导致UB。

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

首先,表达式数组[argc+=7]等于*array+argc+=7,在对+求值之前先对操作数的值求值;运算符+=是赋值,而不是副作用,赋值的值是赋值后argc的结果cf。因此,+=7对于下标有效

<>第二,ARC定义在C++中,而不是否定的CF.所以argc+=7在非常不现实的场景中总是>=7或有符号整数溢出,但仍然是UB


,ub.< /p>如果你问一个关于C++和ub的问题,那么不要标记其他语言。C是一种完全不同的语言,具有其他语义规则和UB的其他点。至于你的问题,除非argc是-6或-7,否则你将使用一个越界索引,这当然是UB。用于索引的表达式必须首先被完全评估,而在C++中,赋值的所有变体都是简单表达式。我的问题是,如果[i+n]总是第一个递增的。德米特里当然是。只有在同一表达式中的其他位置使用argc时,才会出现问题,因为表达式中子表达式的求值顺序以及副作用的传播通常没有定义。@Dmitry您是否想过argc++的语义?该表达式将原始的、增量前的值作为argv的索引;新值仅在下一条语句中可见。但是表达式argc+=1或+=7在增量后具有argc的值。如果argc小于-7或大于-6,但为是,这可能就是问题所在。@PeterA.Schneider argc不应该是负数,除非在main中的其他地方进行了修改。你有一个观点——它是由运行时设置的,我不知道如何使它在main中显示为负数。也许是通过提供INT_MAX+7命令行参数,但恐怕在此之前的某个地方对命令行长度有限制。
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