[英]Casting a Vec* to a double*
我試圖了解我所提供的框架,並對其進行緩慢調試。 在我的情況下,我有一個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;
我意識到try指向第一個Vec,即boh1,因此,如果我去調試,我會看到x,y,z值設置為1。同樣,try2應該指向與boh1相關的“東西”,但是調試顯示我說try2的值為1.000000。 那么,實際發生了什么?
編輯:“ try”不能用作c ++中變量的名稱。
它仍然會為您提供指向Vec
的指針,這根本不是double
。 強制轉換的作用是告訴編譯器完全不考慮try
的實際類型,有效地假裝try
不是。
使用try2
將導致未定義的行為 。
“實際上”正在發生的事情是,由於結構的數據成員是3的兩倍,因此您的同事指望C的行為,他們將內存看作是double
而不是Vec
。 在C語言中,它的作用就像一個“聯合”,也就是說,在內存中布置的結構僅一個接一個的三倍。 在您的情況下(使用C ++),就像聯合一樣發生(請參閱EDIT)。 因此,您正在從boh
中訪問1.0(您稱其為boh1
)。 別人說,行為是不確定的。 我相信“依賴於實現”可能會更准確,但是我會順應他們(除非可以找到參考)。
無論如何,您的代碼示例已經可以重構。 如果您的同事依靠這種行為,他們應該清楚地表明這一點,以使其他人不會來改變這種結構。
編輯 :好的,我發現了一個引用,表明這不是未定義的行為(除非我誤解了該引用)。 根據C ++規范的第9節(ss7,10),該結構是POD結構。 9.2(ss13)中介紹了POD(普通舊數據)布局。
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秒13
分配具有相同訪問控制(第11條)的(非聯盟)類的非靜態數據成員,以便以后的成員在類對象中具有更高的地址。 未指定具有不同訪問控制的非靜態數據成員的分配順序(第11條)。 實施一致性要求可能會導致兩個相鄰成員不能彼此立即分配; 管理虛擬功能(10.3)和虛擬基類(10.1)的空間要求也可能如此。
因此,我懷疑您的同事是依靠POD布局來獲得類似“工會”的行為。 我仍然認為這是非常糟糕的做法。 如果無法避免,則應添加編譯時檢查或記錄結構以識別此要求。
正如其他人指出的那樣,您正在做的事情是非常錯誤的-我不再贅述。
try
是一個指針,因此它是Vec * try = new Vec[2];
之后的值Vec * try = new Vec[2];
是分配數組的一些內存地址。
當你做double* try2 = (double*)try;
您要告訴編譯器獲取try
的值並將其復制到try2
。 就是這樣-該值即一個內存地址正在被復制。
之后,如果您觀察*try2
存在什么值,則會在*try2
指向的地址處看到一個double
try2
值的文本表示try2
。 由於您將Vec
結構復制到該地址,因此您將看到的值來自該數據,該數據在相對存儲位置0處為double
Vec
值-這是Vec
的x
成員,您將其分配了1.0。
同樣,所有這些都可以並且應該被認為是巧合,因此您一開始就不應該進行此類轉換。
您的程序的行為是不確定的。
本質上, sizeof(double)
與sizeof(Vec)
因此所有指針算術和數組索引將在C樣式強制轉換后分解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.