我想使用模板在C 中撰寫數字搜索樹。為了做到這一點,給定一個型別T和型別T的資料,我必須在這個資料的位上進行迭代。在整數上做到這一點很容易,我們只需將數字向右移動適當的位置,然后用1來"& "這個數字,就像這里描述的那樣如何獲得第n位的值。當人們試圖從模板化的資料中獲取第i'th位時,問題就開始了。我寫的東西是這樣的
#include <iostream>
template<typename T>
bool getIthBit (T data, unsigned int bit){
return ((*((char*)& data) (bit>> 3)))>>(bit&7))& 1。
}
int main() {
uint32_t a = 16;
for (int i =0; i < 32; i ) {
std::cout << getIthBit(a, i)。
}
std::cout << std::endl;
}
這可以作業,但我不太確定這是否是未定義的行為。這樣做的問題是,要遍歷資料的所有位,必須知道其中有多少位,這對結構資料型別來說是很難的,因為有填充。例如這里
#include <iostream>
結構 s {
uint32_t i;
char c;
};
int main() {
std::cout << sizeof (s) << std::endl;
}
實際資料有5個位元組,但程式的輸出說它有8個。我不知道如何獲得資料的實際大小,或者是否有可能。這里有一個關于這個問題的提問 如何檢查結構的大小(無填充)? ,但答案只是 "不知道"。
uj5u.com熱心網友回復:
要知道一個型別中有多少個位元是很容易的。正是有 我建議不要試圖支持那些有填充物的型別作為你的 DST 的鍵。
下面的技巧可能適用于尋找瑣碎的可復制類的填充位:
我不確定是否有任何技術上的保證,即填充物實際上保持為0,所以這是否有效可能還沒有明確的說法。此外,可能有一些非類有填充,而所描述的技巧不會檢測到這些。 因此,有很多注意事項,但它在你的例子中應該是可行的: uj5u.com熱心網友回復: 有一種標準的方法可以知道一個型別是否有唯一的表示。它就是 因此,如果一個物件有唯一的表示法,就可以安全地假設每一個位元都是有意義的。
沒有標準的方法來知道非唯一表示是否由填充位元組/位引起,就像在 注意,"實際大小 "的概念可能是誤導性的,因為padding可以在中間,就像在 在內部,編譯器必須區分padding位和value位,以實作C 20
1像多個NaN浮點值
標籤: 下一篇:模板的使用沒有角括號-超載?
CHAR_BIT * sizeof(T)/code>。sizeof(T)是該型別的實際大小,單位是位元組。但事實上,在標準的C 中并沒有一種普遍的方法來知道這些位中的哪一個--屬于型別的一部分--是填充的。
std::memset來設定物件的所有位為0。
std::memset將所有位設定為1.long double是典型的例子;我不知道是否還有其他的。這可能不會檢測到位域下的整數的未使用的位。
s sobj;
std::memset(&sobj, 0, sizeof sobj)。
std::memset(&sobj.i, -1, sizeof sobj.i) 。
std::memset(&sobj.c, -1, sizeof sobj.c) 。
std::cout << "非填充位。
"。
unsigned long long ull;
std::memcpy(&ull, &sobj, sizeof sobj);
std::cout << std::bitset<sizeof sobj * CHAR_BIT> (ull) << std::endl。
std::has_unique_object_representations,從C 17開始可用。struct { long long a; char b; }中一樣,或者由等價表示引起1。也沒有標準的方法來知道填充的位元/位元組的偏移量。
struct { char a; long long b; }atomic<T>::compare_exchange_*。MSVC通過使用__builtin_zero_non_value_bits將填充位清零來實作。其他編譯器可能使用其他名稱,另一種方法,或不暴露atomic<T>::compare_exchange_*的內部結構到這個級別。
