【问题标题】:Iterating through a vector of stucts's members with pointers and offsets Part 2使用指针和偏移量遍历结构成员的向量第 2 部分
【发布时间】:2019-01-31 17:15:52
【问题描述】:

所以这是我昨天提出并得到回答的问题的第 2 部分。所以今天我带着第 2 部分回来。我不确定这是否应该在其他地方,所以如果版主想要移动它,请随意。

所以我不打算在这里重新介绍我的问题,所以请阅读第 1 部分 Iterating through a vector of stucts's members with pointers and offsets

所以我想出了一个解决问题的方法,所以让我发布一个修改后的 sn-p 代码,代表我想要的解决方案,

#include <iostream>
#include <vector>

// knows nothing about foo
class Readfoo
{ 
    private:
    int offSetSize;
    char* pchar;

    public:
    void SetPoint(double* apstartDouble, int aoffSetSize)  
    {
        offSetSize = aoffSetSize;
        pchar = static_cast<char*> (static_cast<void*>(apstartDouble));
    };

    const double& printfoo(int aioffset) const
    {
       return *(static_cast<double*> (static_cast<void*>(pchar + aioffset*offSetSize)));
    };
};

// 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);
    for(int ii = 0; ii < bar.size(); ii++) 
        bar[ii].b[2] = ii;

    // access b[2] for each foo using an offset.
    Readfoo newReadfoo;
    newReadfoo.SetPoint(&(bar[0].b[2]), sizeof(foo)/sizeof(char));
    for(int ii = 0; ii < bar.size(); ii++)
        std::cout<<"\n"<<newReadfoo.printfoo(ii);

    return 0; 
}

在我看来,这是合法的,我想这就是我要问的。从现在开始,本质上,我正在将我对 struct foo 和向量 bar(foo 数组)的“解释”转换为单个字节数组或字符数组。

即在这种解释中,数据结构是单个字符数组,大小为 foo 乘以 bar 大小。当我用一个整数类型遍历它时,我本质上是在移动到一些假设的 char 元素(第 1 部分答案中的第 4.2 点)。 printfoo 函数然后将接下来的 8 个字节组合成一个双精度返回。

那么这是合法的吗?除了超出条形向量的范围之外,还有什么原因导致这不起作用(我已经测试过了,它还没有失败。)?

【问题讨论】:

  • 您无法从观察程序中看出它没有具有未定义的行为。
  • sizeof(foo)/sizeof(char) 将为bar 中的第二个元素提供偏移量。 sizeof(char) 始终是 1
  • @DavidC.Rankin 我意识到 sizeof(foo)/sizeof(char) 基本上是 sizeof(char) 并且相当多余
  • 如果您首先删除对static_cast&lt;void*&gt; 的强制转换,您的编译器是否不会警告"invalid static_cast from type ‘double*’ to type ‘char*’"?这不会为您带来危险信号吗? (您永远不应该转换为 void* 以避免静态转换错误)。您可以强制转换为 char*(例如 pchar = (char*)apstartDouble;)而不违反严格混叠规则,但直接静态强制转换会失败。除了简单地研究指针和寻址之外,您还试图完成什么?
  • 再次绕道void*char*void*,原问题中的代码不会突然变得合法。它现在工作并不意味着你的编译器以后不会找到一些有趣的优化(在进一步的代码更改之后),因为代码没有遵循规则,所以会破坏你的程序。

标签: c++ pointers iteration pointer-arithmetic


【解决方案1】:

这样合法吗……

不,不是。

在下面的表达式中:

pchar + aioffset*offSetSize

您操纵pchar,就好像它是一个指向char 数组的指针,但事实并非如此(它是一个指向double 数组的指针)。这是未定义的行为:

[expr.add]/6

对于加法或减法,如果表达式PQ 的类型为“pointer to cv T”,其中T 和数组元素类型不相似,则行为未定义。 [ 注意:特别是,当数组包含派生类类型的对象时,指向基类的指针不能用于指针运算。 — 尾注 ]

在您的情况下,Ppchar 并且具有指向 char 的类型指针,但它指向的数组元素是 double


...除了超出条形向量的范围之外,还有什么原因导致这不起作用(我已经对其进行了测试,但尚未失败。)?

是的:Does the C++ standard allow for an uninitialized bool to crash a program?


更进一步:C++ 中的指针操作是一个危险信号。 C++ 指针操作是一种黑魔法,它会燃烧你的灵魂并吞噬你的狗。 C++ 提供了很多工具来编写通用代码。我的建议:询问您想要实现的目标,而不是您尝试的解决方案。你会学到很多东西。

【讨论】:

  • 好吧,无论如何我都会使用它,因为它可以工作,并且可以解决我遇到的可预见问题,而且我没有理由看到编译器如何知道它是不通过 char 数组移动,因此必须实现它具有 char + 一些字节数。但是当我被烫伤时,我会来这里告诉你我被烫伤了,你可以说,“我告诉过你” 回复:你的最后评论,这可能是黑魔法,但老实说指针操纵和'接近硬件类型操作是 C++ 胜过其他语言的地方。
  • 我不知道我是否在争论 symatics,但作为回应,'在你的情况下,P 是 pchar 并且具有指向 char 的类型指针,但它指向的数组元素是双精度数',但 double 只是一个 8 个字符的数组。所以 pchar 指向数组的第一个字节...
  • 我告诉过你(只是来早了,暂时忽略我)。
  • "但是 double 只是一个 8 个字符的数组" 这在语义上肯定不是真的,尽管你可以逐字节检查 memoy。但是从char* 读取double 肯定是标准的UB。
  • 注意:通过"a char or unsigned char type." 访问并不违反严格的别名规则——然而,这确实让程序员有100% 的责任避免未定义的行为
猜你喜欢
  • 2019-06-23
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多