我正在尝试理解我提供的框架并慢慢调试它。在我的例子中,我有一个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 ++中变量的名称。
答案 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)类型的元素(下面定义)作为基类.1099.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风格的转换后分解。