将Vec *投射到双*

时间:2015-10-14 10:37:30

标签: c++ arrays casting

我正在尝试理解我提供的框架并慢慢调试它。在我的例子中,我有一个Vec数组,用指针记忆:

maxZoom

My Vec是一个定义如下的结构:

minZoom

我想知道如果我将一个Vec数组转换为双数组,实际会发生什么。在实践中:

Vec *cx =....;

它给了我什么回报?

为了理解,我试图这样做:

struct Vec {
    double x, y, z;                  // position, also color (r,g,b)
    Vec(double x_ = 0, double y_ = 0, double z_ = 0){ x = x_; y = y_; z = z_; }
    Vec operator+(const Vec &b) const { return Vec(x + b.x, y + b.y, z + b.z); }
    Vec operator-(const Vec &b) const { return Vec(x - b.x, y - b.y, z - b.z); }
    Vec operator-() const { return Vec(-x, -y, -z); }
    Vec operator*(double b) const { return Vec(x*b, y*b, z*b); }
    Vec mult(const Vec &b) const { return Vec(x*b.x, y*b.y, z*b.z); }
    Vec& norm(){ return *this = *this * (1 / sqrtf(x*x + y*y + z*z)); }
    double dot(const Vec &b) const { return x*b.x + y*b.y + z*b.z; } // cross:
    Vec operator%(Vec&b){ return Vec(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); }
    double max() const { return x>y && x>z ? x : y > z ? y : z; }
};

我意识到尝试指向第一个Vec,即boh1,所以如果我去调试,我会看到x,y,z值设置为1.同样,try2应该指向与boh1相关的“某事”,但是调试显示try2的值为1.000000。那么,究竟发生了什么?

编辑:“try”不能用作c ++中变量的名称。

4 个答案:

答案 0 :(得分:4)

它仍会指向Vec的指针,它根本不是double。演员所做的是告诉编译器完全忽略try的实际类型,有效地假装try不是它。

使用try2会导致未定义的行为

答案 1 :(得分:1)

什么是"实际上"发生的事情是,由于你的结构的数据成员是3个双打,你的同事正在指望C行为,他们将内存看作double而不是Vec。在C中,它就像一个" union",就是在内存中布局的结构只有3个双打一个接一个。在你的情况下(使用C ++),它恰好发生(参见EDIT)就像一个联盟。因此,您从boh访问1.0(因为您称之为boh1)。其他人说,这种行为是不确定的。我相信"实施依赖"可能更准确,但我会推迟他们(除非我能找到参考)。

无论如何,如果可以的话,您的代码示例已经成熟,可以进行重构。如果你的同事依赖这种行为,他们应该清楚地确定这一点,以便其他人不会来并改变结构。

编辑:好的,我找到了一个引用,表明这是 NOT 未定义的行为(除非我误解了引用)。根据C ++规范的第9节(ss7,10),结构是一个POD结构。 POD(普通旧数据)布局在9.2(ss13)中描述。

  

9 ss10
POD struct110是一个非联合类,它既是一个普通的类又是一个标准布局类,并且没有非POD结构类型的非静态数据成员,非POD联合(或这些类型的数组)。类似地,POD联合是一个简单类和标准布局类的联合,并且没有非POD结构类型的非静态数据成员,非POD联合(或这种类型的数组)。 POD类是POD结构或POD联合的类。

     

9 ss7
如果一个S类是标准布局类:   
- (7.1)没有类型非标准布局类(或这类类型的数组)或引用的非静态数据成员,   
- (7.2)没有虚函数(10.3)且没有虚基类(10.1),   
- (7.3)对所有非静态数据成员具有相同的访问控制(第11条),   
- (7.4)没有非标准布局基类,   
- (7.5)最多有一个任何给定类型的基类子对象,   
- (7.6)具有类中的所有非静态数据成员和位字段,并且它们的基类首先在同一个类中声明,并且   
- (7.7)没有集合M(S)类型的元素(下面定义)作为基类.109

     

9.2 ss13
分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。具有不同访问控制的非静态数据成员的分配顺序未经指定(第11条)。实施对齐要求可能导致两个相邻成员不能立即分配;因此,可能需要空间来管理虚拟功能(10.3)和虚拟基类(10.1)。

因此,我怀疑你的同事是否依赖POD布局以获得" union"喜欢的行为。我仍然认为这是一个非常糟糕的做法。如果无法避免,则应添加编译时检查或记录结构以确定此要求。

答案 2 :(得分:1)

正如其他人指出的那样,你所做的是非常错误的 - 我不会再重复细节了。

<小时/> 为什么你在调试器中看到1.0000?为此,原因如下:

try是一个指针,因此Vec * try = new Vec[2];之后的值是分配数组的内存地址。
当您执行double* try2 = (double*)try;时,您告诉编译器获取try的值并将其复制到try2。就是这样 - 正在复制值,即内存地址。

之后,如果您观看*try2中存在的值,您会在double指向的地址处看到try2值的文字演示。由于您将Vec结构复制到该地址,因此您将看到的值来自该数据,该数据在相对内存位置0处具有double - 即x成员{ {1}},您已将1.0指定为。

同样,所有这些都可以而且应该被认为是巧合,你不应该开始这样的演员。

答案 3 :(得分:0)

程序的行为未定义。

基本上,sizeof(double)sizeof(Vec)不同,因此所有指针算术和数组索引都将在C风格的转换后分解。