我正在尝试通过不像我目前那样多地追踪指针来优化一段代码。我想创建一个常量偏移量以添加到存储的指针中,以获取下一个数据条目,请参见下面的代码。但是,数据位于类或结构的旁边,包含不同的数据类型。
所以我在下面的代码段中得到了正确的行为,即输出为1、2、3。
#include <iostream>
#include <vector>
// knows nothing about foo
class Readfoo
{
private:
int offset;
double* pdouble;
public:
void SetPoint(double* apdouble, int aoffset)
{
offset = aoffset;
pdouble = apdouble;
};
const double& printfoo(int aidouble) const
{
return *(pdouble + offset*aidouble);
};
};
// knows nothing about readFoo
struct foo
{
int a[5];
double b[10];
};
int main()
{
// populate some data (choose b [2] or other random entry.).
std::vector<foo> bar(10);
bar[0].b[2] = 1;
bar[1].b[2] = 2;
bar[2].b[2] = 3;
// access b[2] for each foo using an offset.
Readfoo newReadfoo;
newReadfoo.SetPoint(&(bar[0].b[2]), sizeof(foo)/sizeof(double));
for(int ii = 0; ii < 3; ii++)
{
std::cout<<"\n"<<newReadfoo.printfoo(ii);
}
return 0;
}
我的问题有两个:
答案 0 :(得分:6)
不,这不是合法的C ++。仅当您停留在同一数组(或数组末尾的数组)内时,才定义指针算术。
将具有整数类型的表达式
J
添加到指针类型的表达式P
或从中减去时,结果的类型为P
。
(4.1) 如果
P
的值为空指针值,而J
的值为0
,则结果为空指针值。(4.2) 否则,如果
P
指向具有n个元素的数组对象x[i]
的元素x
,则表达式P + J
和J + P
(其中J
具有如果j
的值x[i+j]
指向(可能是假设的)元素0≤i+j≤n
,而表达式P - J
则指向{可能是假设的)元素x[i−j]
如果是0≤i−j≤n
。(4.3) 否则,行为是不确定的。
(4.1)不适用,因为您未在nullptr
上进行操作。 (4.2)不适用,因为您正在使用double*
,因此标准引号中的x
必须是double
数组,即结构的b
成员。根据其余的(4.3),使用指针算法来限制边界是不确定的行为。
您要在此处进行的操作恰恰是一个好的编译器应该(并且将要)在后台进行的操作:
volatile double output;
void bar(std::vector<foo> bar, int innerOffset)
{
for (foo& f : bar)
output = f.b[innerOffset];
}
请注意反汇编如何执行所需的指针算术(因为编译器知道它在目标平台上有效)。这是最里面的循环:
.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]
表达式可免费执行所有其他指针算法。