且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

遍历带有指针和偏移量的stucts成员向量

更新时间:2023-02-26 13:52:57

否,这不是合法的C ++.仅当您停留在同一数组(或数组末尾)内时,才定义指针算术.

No, this is not legal C++. Pointer arithmetic is only defined if you stay inside the same array (or one past its end).

expr.add#4

将具有整数类型的表达式J添加到指针类型的表达式P或从中减去时,结果的类型为P.

When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.

  • (4.1) 如果P计算为空指针值,而J计算为0,则结果为空指针值.

  • (4.1) If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

(4.2) 否则,如果P指向具有n个元素的数组对象x的元素x[i],则表达式P + JJ + P(其中J的值为j)指向(可能是-如果0≤i+j≤n,则假定元素x[i+j],如果0≤i−j≤n,则表达式P - J指向(可能是假想的)元素x[i−j].

(4.2) Otherwise, if P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i+j] if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) element x[i−j] if 0≤i−j≤n.

(4.3) 否则,行为是不确定的.

(4.3) Otherwise, the behavior is undefined.

(4.1)不适用,因为您未在nullptr上进行操作. (4.2)不适用,因为您正在使用double*,因此标准引号中的x必须是double数组,即结构的b成员.根据其余的(4.3),使用指针算法来限制边界是不确定的行为.

(4.1) does not apply because you're not operating on nullptrs. (4.2) does not apply because you are working with double*, so x in the standard quote must be a double array, i.e. the b member of your struct. Leaving its bounds with pointer arithmetic, according to the remaining (4.3), is undefined behavior.

您要在此处进行的操作恰恰是一个好的编译器应该(并且将要)在后台进行的操作:

What you are trying to do here is exactly what a good compiler should (and will) do under the hood anyway:

volatile double output;

void bar(std::vector<foo> bar, int innerOffset)
{
    for (foo& f : bar)
        output = f.b[innerOffset];
}

https://godbolt.org/z/S9qkTf

请注意反汇编如何执行所需的指针算术(因为编译器知道它在目标平台上可以正常工作).这是最里面的循环:

Notice how the disassembly does the pointer arithmetic you want (because the compiler knows that it works on the target platform). Here is the innermost loop:

.L3:
    movsd   xmm0, QWORD PTR [rax+24+rsi*8]
    add     rax, 104
    movsd   QWORD PTR output[rip], xmm0
    cmp     rdx, rax
    jne     .L3

104个字节恰好是一个foo的大小. [rax+24+rsi*8]表达式免费进行所有附加的指针运算.

104 bytes is exactly how big one foo is. The [rax+24+rsi*8] expression is doing all the additional pointer arithmetic for free.