2015-10-14 76 views
1

我想了解一个框架,我已经提供并慢慢调试它。在我来说,我有VEC的数组,指针记忆:铸造Vec *为双倍*

Vec *cx =....; 

我VEC是定义为一个结构如下:

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数组到双精度数组。在实践中:

double * cast = (double*)cx; 

它给我什么回报?

为了了解,我试着这样做:

Vec boh = Vec(1.0, 1.0, 1.0); 
Vec boh2 = Vec(2.0, 2.0, 2.0); 
Vec * try = new Vec[2]; 
try[0] = boh; 
try[1] = boh2; 
double* try2= (double*)try; 

我意识到,试图指向第一个VEC,这是boh1,所以如果我去调试,我看到了X,Y,Z值设置为1.同样,try2应指向与boh1相关的“某些内容”,但调试显示try2的值为1.000000。那么,究竟发生了什么?

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

+7

我不推荐在C++中使用'try'作为变量名称。 –

+0

@PaulR是别担心..我只是懒编辑文本。我现在要做,以避免误解。 – Tarta

回答

4

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

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

0

程序的行为是未定义的。

本质上,sizeof(double)sizeof(Vec)不一样,因此所有指针算术和数组索引都会在C风格转换后崩溃。

1

什么是“实际”发生的事情是因为你的结构的数据成员是3双打,你的同事指望C行为,他们把内存视为double而不是Vec。在C语言中,它会像“联盟”一样行事,那就是结构在内存中的结构是一个接一个的三倍。在你的情况下(使用C++),它恰好发生了(参见编辑)像联合一样行事。所以你从boh访问1.0(因为你称之为boh1)。其他人说,行为是不确定的。我相信“依赖实施”可能更准确,但我会推迟给他们(除非我能找到参考)。

无论如何,你的代码示例已经成熟,可以重构。如果你的同事依靠这种行为,他们应该清楚地识别出来,以便其他人不会来改变结构。

编辑:好吧,我发现,表明这是未定义行为(除非我误解参考)的参考。该结构是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.3)对于所有非静态数据成员具有相同的访问控制(条款11),而对于所有非静态数据成员,(7.2)没有虚拟功能(10.3)并且没有虚拟基类(10.1),
- (7.4) )没有非标准布局基类,
- (7.5)最多只有一个给定类型的基类子对象,
- (7.6)具有所有非静态数据成员和b在类IT-音响视场和它的基类在同一类中第一个声明,并且
- (7.7)不具有的类型的集合M(S)的元素(下面德音响NED)作为碱class.109

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

因此,我怀疑你的同事是依靠POD布局以获得“工会”般的行为。我仍然认为这是一个非常糟糕的做法。如果无法避免,应该添加编译时检查,或者应该记录结构来确定这个要求。

1

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


为什么在调试器中看到1.0000?为此,原因如下:

try是一个指针,因此它的值是在Vec * try = new Vec[2];之后是数组分配的内存地址。
当你这样做double* try2 = (double*)try;你告诉编译器采取try s值并将其复制到try2。只是 - 正在复制内存地址的值。然后,如果您看到*try2上存在什么值,则会在try2指向的地址处看到一个double值的文本表示。由于您将Vec结构复制到该地址,因此您将看到的值来自该数据,该数据在相对内存位置0处具有double - 即您为其指定1.0的Vecx成员。

再说一次,所有这些都可以而且应该被认为是巧合的,你不应该从头开始。