有人可以告诉我这种构造在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
所以,我可以假设这样的酒是一种标准的酒吗?
答案 0 :(得分:4)
对于a[i+=N]
,在访问索引之前,将始终首先对表达式i += N
求值。但是您提供的示例将调用UB,因为示例数组仅包含两个元素,因此您正在访问数组的边界。
答案 1 :(得分:4)
就array[argc += 7]
本身而言还可以,argc + 7
的结果将用作array
的索引。
但是,在您的示例中,array
仅包含2个元素,并且argc
永远不会为负,因此,由于越界访问数组,您的代码将始终导致UB。
答案 2 :(得分:2)
您的情况显然是未定义的行为,因为由于以下原因,您将超出数组范围:
首先,表达式array[argc += 7]
等于*((array)+(argc+=7))
,并且在计算+
之前先对操作数的值求值(参见here);运算符+=
是赋值(而不是副作用),赋值是赋值后的argc
(在这种情况下)的结果(请参见here)。因此,+=7
对下标有效;
第二,argc
在C ++中定义为永不为负(参见here);因此,argc += 7
将始终为>=7
(或者在非常不现实的情况下会出现有符号整数溢出,但那时仍然是UB)。
因此,UB。
答案 3 :(得分:1)
这是正常行为。实际上数组的名称是指向数组第一个元素的指针。并且array [n]与*(array + n)
相同