簡體   English   中英

將Vec *轉換為雙倍*

[英]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)的元素類型(如下定義)作為基類。109

9.2秒13
分配具有相同訪問控制(第11條)的(非聯盟)類的非靜態數據成員,以便以后的成員在類對象中具有更高的地址。 未指定具有不同訪問控制的非靜態數據成員的分配順序(第11條)。 實施一致性要求可能會導致兩個相鄰成員不能彼此立即分配; 管理虛擬功能(10.3)和虛擬基類(10.1)的空間要求也可能如此。

因此,我懷疑您的同事是依靠POD布局來獲得類似“工會”的行為。 我仍然認為這是非常糟糕的做法。 如果無法避免,則應添加編譯時檢查或記錄結構以識別此要求。

正如其他人指出的那樣,您正在做的事情是非常錯誤的-我不再贅述。


為什么在調試器中看到1.0000? 為此,原因如下:

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值-這是Vecx成員,您將其分配了1.0。

同樣,所有這些都可以並且應該被認為是巧合,因此您一開始就不應該進行此類轉換。

您的程序的行為是不確定的。

本質上, sizeof(double)sizeof(Vec)因此所有指針算術和數組索引將在C樣式強制轉換后分解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM