通过指针访问非数组浮点数

Accessing non-array floats via pointers

本文关键字:数组 浮点数 访问 指针      更新时间:2023-10-16

这是有效/可移植/合法的代码吗?

class Vector3
{
public:
  float& operator [] ( const size_t i )
  {
    assert( i < 3 );
    return *(&x+i);
  }
  float x, y, z;
};

有相当多的实例,我想使用[]操作符,最终把元素放在一个数组中(以避免if/switch语句)。我从来没有用这种方法做过。我可以告诉为什么它工作(x,y和z是连续的),但它是好的(或至少是ok的)实践?

另外,代码是否要求#pragma pack 1保证无垫包装,或者没有它可以工作?我问的原因是,因为片段实际上是从Ogre3D矢量类,我没有看到#pragma pack 1在任何地方。

No。这是不正确的,也不是好的做法。很可能在三个元素之间没有填充(即使没有指示编译器打包结构),因此您很可能能够像访问数组元素一样访问成员。但是,这并不能使代码正确:所写的代码会产生未定义的行为。

正确的方法是为组件使用访问器函数,例如

struct Vector 
{
    float& operator[](std::size_t i)       { return data_[i]; }
    float  operator[](std::size_t i) const { return data_[i]; }
    float& x() { return data_[0]; }    
    float& y() { return data_[1]; }    
    float& z() { return data_[2]; }
    float x() const { return data_[0]; }
    float y() const { return data_[1]; }
    float z() const { return data_[2]; }
private:
    float data_[3];
};

我相信它确实有效,因为c++编译器不允许在单个访问说明符内重新排序类/结构的成员-所以它们总是必须排列为x, y, z。这是为了向后兼容C,在C中编译器根本不允许重新排序成员。

然而,我认为这对它自己来说有点太聪明了。对我来说,在操作符内部设置几个if或开关似乎更干净,尽管我猜他们可能认为如果它是一个Ogre向量,那么它可能是性能关键的,所以这可能是这样做的原因。

我不认为包装pragma是必要的,因为所有三个成员都是相同的大小,所以你会期望他们彼此有关。但我并不是百分百肯定。

如果代码假设32位浮点是连续的,那么64位机器将结构元素对齐到64位边界将失败,很可能没有警告。

仅仅因为它在我所知道的所有32位和16位架构中的所有实现上都有效,并不意味着它通常有用。最好的情况下,它是一个特殊的情况下,工作在多个实现。据推测,未来将出现128位和256位架构,在这些架构中,它可能会像奇怪的那样失败。

这些隐藏的假设给那些继承了这些代码的人带来不必要的痛苦和折磨——如果你忘记了它,甚至可能是你。它的表达方式如此可疑,以至于很难理解任何微薄的利益都被证明是为了什么利益而进行的交易。请学习KISS原则。知道。住它。喜欢它。