[英]How do i copy members of a struct into an array of double in C?
我有一個這樣的成員的結構
typedef struct{
double xMin;
double yMin;
double zMin;
double xMax;
double yMax;
double zMax;
double xMedian;
double yMedian;
double zMedian;
double xMean;
double yMean;
double zMean;
double xVar;
double yVar;
double zVar;
double xStD;
double yStD;
double zStD;
}featureSet_t;
typedef struct{
featureSet_t acc_features;
featureSet_t gyr_features;
featureSet_t mag_features;
}combinedFeatureSet_t;
combinedFeatureSet_t featureSetOfPolledData;
double copy[54] = {0};
現在我想將上述實例的成員復制到重復說的數組中,例如,
copy[0] = featureSetOfPolledData.acc_features.xMin;
..
..
copy[53] = featureSetOfPolledData.mag_features.zstD;
太乏味了。 請幫助實現此目的的最佳方法。
最好的解決方案是簡單地使用memcpy。 您需要防止在結構中進行填充-在這種情況下應該沒有填充,但是最好始終進行編譯時檢查:
_Static_assert(sizeof(featureSetOfPolledData) == sizeof(double[54]),
"Unexpected padding detected.");
一旦檢查完成,就可以輕松地進行以下操作:
memcpy(copy, &featureSetOfPolledData, sizeof(double[54]));
如果出於某種原因需要索引各個項目名稱,並且可以更改類型,請考慮使用聯合:
typedef union
{
struct
{
double xMin;
double yMin;
double zMin;
double xMax;
double yMax;
double zMax;
double xMedian;
double yMedian;
double zMedian;
double xMean;
double yMean;
double zMean;
double xVar;
double yVar;
double zVar;
double xStD;
double yStD;
double zStD;
};
double array [18];
}featureSet_t;
typedef union
{
struct
{
featureSet_t acc_features;
featureSet_t gyr_features;
featureSet_t mag_features;
};
double array [18*3];
}combinedFeatureSet_t;
現在可以執行以下操作:
for(size_t i=0; i<54; i++)
{
copy[i] = featureSetOfPolledData.array[i];
}
還可以通過名稱訪問單個項目:
featureSetOfPolledData.acc_features.xMin = 1.0;
隆丁提供了一個很好的答案
這個答案不是解決方案。 它更多地是警告您不應該執行的常見操作。 做這樣的事情可能很誘人,但您不應該這樣做。
double *ptr = &featureSetOfPolledData;
for(int i=0; i<53; i++) copy[i] = ptr[i];
這可能有效,但確實會引發未定義的行為。
那么,為什么這會導致不確定的行為呢? 這並不完全明顯。 保證結構中的成員與您編寫它們的順序相同。 填充可以在結構中發生,但是對於double而言,任何編譯器都不太可能使用填充。
老實說,我不記得詳細信息,但是這與通過指針訪問字段有關,這只是C標准中的未定義行為,任何未定義行為都可能會破壞您的代碼。 特別是在啟用優化的情況下。
隆丁(又是一位偉人)在以下評論中寫道:
之所以是UB,是因為結構布局不能保證與double保持相同的對齊方式(實際上,在這種情況下,它會保持對齊),而且還因為featureSetOfPolledData不是數組。 該標准的一部分是加法運算符C17 6.5.6“出於這些運算符的目的,指向不是數組元素的對象的指針的行為與指向長度為1的數組的第一個元素的指針相同。以對象的類型作為其元素類型。” 然后,您將超越1個元素的大型數組。 允許編譯器假定您沒有訪問數據。
C17 6.3.2.3給出了一個特殊的例外,該例外允許您使用字符類型來剖析較大的類型。 因此,僅作記錄用途,您實際上可以通過使用字符類型來進行這種定義良好的操作,在每次迭代時將其以sizeof(double)增加,然后轉換為double。 喜歡
for(uint8_t* ptr = &featureSetOfPolledData; ptr < (uint8_t*)&featureSetOfPolledData + sizeof(double[54]); ptr += sizeof(double)) { double d = *(double*)ptr; /* Put the copying code here */ }
完全瘋狂,但定義明確
正如您所描述的,將結構成員分別分配給您的數組是完成這項工作的唯一嚴格一致的方法。 任何其他替代方法都需要對struct成員的布局進行假設,並且C不能對此做出足夠有力的保證來支持您想要的內容。
但是,如果您願意假設featureSet_t
的布局在成員之間沒有任何填充,或者您可以使用實現擴展來確保,並且如果要按結構成員順序填充數組,則可以在結構后添加一個結構的成員。其他的,則可以使用memcpy()
進行此操作:
double copy[54];
memcpy(copy, &featureSetOfPolledData.acc_features, 18 * sizeof(double));
memcpy(copy + 18, &featureSetOfPolledData.gyr_features, 18 * sizeof(double));
memcpy(copy + 36, &featureSetOfPolledData.mag_features, 18 * sizeof(double));
這樣就可以實現相當不錯的代碼簡單性,以換取關於結構布局的一些重要假設,但這些假設在實踐中可能仍然適用。 可以想象,您可能只需要整個featureSetOfPolledData
對象的一個memcpy()
就可以了,但是IMO,以這種方式實現的最少的附加代碼簡化並不能證明對布局的更強假設。
就遵循標准而言,最有效的方法是創建struct和數組的並union
,並驗證它們的大小相同:
static_assert(sizeof(combinedFeatureSet_t) == sizeof(double [54]), "size mismatch");
typedef union {
combinedFeatureSet_t featureset_struct;
double featureset_list[54];
} featureset_u;
featureset_u u;
u.featureset_struct = featureSetOfPolledData;
// read u.featureset_list
static_assert
驗證該結構沒有內部填充。 這樣,數組成員將完全覆蓋struct成員,並且它們具有相同的類型。
使用此聯合,您可以自由地從數組中讀取並寫入結構,反之亦然。
您可能可以創建一個函數,該函數采用combinedFeatureSet_t
並返回一個double array
。 它調用另一個函數,從featureSet_t
為每個featureSet_t
返回一個double array
featureSet_t
double array
。 從那里,您只需要調用第一個函數即可獲取array
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.