2015-06-26 103 views
8

將雙精度數組轉換爲由雙精度值構成的結構可以嗎?將雙數組轉換爲雙精度結構

struct A 
{ 
    double x; 
    double y; 
    double z; 
}; 

int main (int argc , char ** argv) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = static_cast<A*>(static_cast<void*>(arr)); 
    std::cout << a->x << " " << a->y << " " << a->z << "\n"; 
} 

這將打印1 2 3。但是它保證每次使用任何編譯器都能正常工作嗎?

編輯:根據

9.2.21:一個指針到一個標準的佈局結構對象,適當地轉換的α使用reinterpret_cast,指向其初始成員(...),反之亦然。

,如果我代替我的

struct A 
{ 
    double & x() { return data[0]; } 
    double & y() { return data[1]; } 
    double & z() { return data[2]; } 
private: 
    double data[3]; 
}; 

int main (int, char **) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a->x() << " " << a->y() << " " << a->z() << "\n"; 
} 

代碼,那麼它是保證工作。正確?我明白,許多人不會覺得這是令人愉快的,但是在使用結構而不必複製輸入數組數據方面有優勢。我可以在該結構中定義成員函數來計算標量和向量乘積,距離等,這將使我的代碼比我使用數組更容易理解。

如何

int main (int, char **) 
{ 
    double arr[6] = {1.0,2.0,3.0,4.0,5.0,6.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a[0].x() << " " << a[0].y() << " " << a[0].z() << "\n"; 
    std::cout << a[1].x() << " " << a[1].y() << " " << a[1].z() << "\n"; 
} 

這也能保證工作或編譯器可以把一些數據成員經過這麼說sizeof(A) > 3*sizeof(double)?是否有任何可移植的方法來防止編譯器這樣做?

+0

任何人都可以編寫一個編譯器,所以這是一個棘手的問題。爲什麼不指定要使用的編譯器?我的猜測是,所有主要的編譯器都處理這個問題,它確實有效。 –

+0

由於[數據結構對齊](https://en.wikipedia.org/wiki/Data_structure_alignment) –

+0

,您很可能沒有(如果您不想使用雙倍存在的情況)您打破了嚴格的別名規則。 – Jarod42

回答

8

不,不能保證。

xy,或y之間和z之間插入填充,禁止任何編譯器的唯一的事情是常識。任何語言標準都沒有規定會禁止它。

即使沒有填充,即使A的表示與double[3]的表示完全相同,它仍然無效。該語言不允許你假裝一種類型實際上是另一種類型。您甚至不允許將struct A { int i; };的實例視爲struct B { int i; };

1

從我所知道的答案是:是的。

唯一可能導致你失敗​​的是#pragma指令,它有一些非常不尋常的結構設置。例如,如果您的計算機上的雙字節佔用8個字節,並且#pragma指令指示將16個字節邊界上的每個成員對齊,這可能會導致問題。除此之外,你很好。

1

沒有它不能保證,即使它應該與我知道的通用架構所有的編譯工作,因爲C語言規範說:

6.2.6陳述的類型 6.2.6.1 General1的所有的表示除了本小節所述的類型外,其他類型都是未指定的。而且它沒有在結構中的默認填充上說什麼。

當然,常見的體系結構最多使用64位,這是這些體系結構的雙倍大小,所以不應該有填充,並且您的轉換應該可以工作。

提防:你明確地調用未定義行爲,並編譯這樣的鑄造時,下一代的編譯器可以做任何事情

-2

我不同意這裏的一致意見。一個有三個雙打的結構,和一個有三個雙打的數組完全相同。除非你專門打包了不同的結構,並且位於奇數處理器上,奇數處理器的雙倍字節數。

這不是內置於語言,但我會覺得安全的做法。風格明智,我不會這樣做,因爲它只是令人困惑。

2

該標準對物體的內存佈局幾乎沒有保證。

對於類/結構:

9.2./15:具有相同的訪問控制的一類非靜態數據成員被分配,使得後來成員一個類對象內具有更高的地址 。未指定具有不同訪問控制的成員的非靜態數據分配順序 。執行 對齊要求可能會導致兩個相鄰的成員不能立即分配到另一個;因此可能需要 空間來管理虛擬功能和虛擬基類。

對於數組,元素是連續的。沒有提到對準,所以它可以或可以不使用相同的對準規則比結構:

8.3.4:陣列類型的對象包含類型爲N子對象的連續分配的非空集合T.

,你可以在你的具體的例子可以肯定的唯一的事情就是a.x對應arr[0],如果使用的reinterpret_cast:

9.2.21:指向標準佈局結構對象的指針,使用reinterpret_cast進行適當轉換,指向其初始成員(...) ,反之亦然。 [
>