2014-10-05 62 views
2

在我以前的question我質疑srand(time(NULL))的便攜性。這個標題爲Using rand()的文件提供了一種「使用時間結果()作爲rand();」的種子的方法。然而,我不明白什麼「只是散列time_t的字節」的意思,也不代表什麼代碼。散列time_t的字節是什麼意思?

unsigned time_seed() 
{ 
    time_t now = time (0); 
    unsigned char *p = (unsigned char *)&now; 
    unsigned seed = 0; 
    size_t i; 

    for (i = 0; i < sizeof now; i++) 
    seed = seed * (UCHAR_MAX + 2U) + p[i]; 

    return seed; 
} 

srand (time_seed()); 

有人可以提供解釋嗎?

+1

http://en.wikipedia.org/wiki/Hash_function – 2014-10-05 21:08:01

+0

警告:完全不清楚此操作是否有效。除非一個類型被唯一地表示,否則散列它的表示是沒有用的。 – 2014-10-05 21:43:19

+0

TBH對於手頭的目的幾乎沒有異議 – MSalters 2014-10-05 23:50:10

回答

0

哈希time_t意味着通過對攜帶當前系統時間的結構中的值應用數學計算(哈希函數)來獲得幾乎唯一的數字,即「指紋」。

這樣,每次運行程序時,都會得到一個不同的值作爲srand的種子。

由於種子會不同,你從rand中隨機數的順序也會不同。

+0

但是,如果退貨時間不同,種子已經*不同了。具有種子「x」的「rand」與種子「x + 1」不同。 – usr2564301 2014-10-05 23:54:06

+0

是的。聲明是time_t值不是可移植的,因爲它們不是由ISO C標準定義的,並且哈希可以從中獲取唯一的int。 – 2014-10-06 04:26:45

1

散列time的結果是爲了避免可預測的種子值。它可以用於你可能沒有像rand這樣的不安全僞隨機數生成器的情況,但仍然不希望客戶端能夠預測出你的僞隨機序列。

有很多方法可以完成散列time_t。一個非常簡單的樸素方法就是簡單地運行正在運行的進程pid。這是Unix系統長期使用的經典方法;儘管如此,它並沒有增加更多的安全性。您還可以從系統中包含其他形式的真熵。其他選擇將涉及適當的散列函數或其他數據點和散列的組合。散列函數的示例包括Bernstein散列,Fowler–Noll–Vo hash或其他加密安全散列,如MD5或SHA1。但是,如果您打算使用密碼安全散列函數,那麼您應該也可以使用密碼安全的隨機數生成器。

因爲這是用C++標記的,所以只要您使用支持TR1或更高版本的C++編譯器,就可以使用標準庫中提供的內置std::hash函數。在GCC中,std::hash函數使用上面提到的FNV散列來實現。

+0

如果你有真正的熵,那麼使用'時間'就沒有意義,只需要使用真正的熵。滾動你自己的密碼是一個壞主意(TM)。 – 2014-10-05 23:01:33

+0

@MattMcNabb我完全同意。我絕對不推薦熵種子'rand'方法,因爲'rand'是一個非常差的僞隨機數發生器*。我只是覺得不得不指出我之前看到過它,其他人可能會覺得它很有用。 – b4hand 2014-10-06 03:16:09

0

article in the link you reference認爲,也不能保證你可以施放time_tunsigned inttime_t依賴於實現,因此鑄造unsigned int不可移植性,但你需要一個unsigned int種子函數srand。文章說:

問題是,time_t是一個受限制的類型,可能不會有意義地轉換爲unsigned int。

提出的解決方案是執行上彌補time_t值的字節hash function,這樣你沒有的便攜性問題。哈希函數將輸入的位序列映射爲一個值,通常在特定的範圍內,在這種情況下,您希望將構成time_t(sizeof time_t)的所有字節映射到無符號整型。良好的散列函數將有一個avalanche effect,這意味着輸入中的小改變(時間改變一秒)將對輸出產生顯着影響(一半的輸出位翻轉)。

至於代碼的功能,它實現了一個哈希函數,它遍歷time_t的每個字節並將其添加到當前種子(模數,無符號大小)的乘積乘以常數UCHAR_MAX + 2U。這個散列函數是一個linear congruential generator。請注意0​​是一個指向無符號字符的指針,用作存儲time_t存儲器的字符數組的基礎。通常情況下,你不應該在C++中這樣做,因爲strict aliasing rule,但是規則有一個例外,它允許你將另一個類型作爲字符數組(別名或無符號)進行別名。

+1

我很肯定這篇文章對於'time_t'錯誤。 'time_t'保證是這裏所述的原始整型之一的別名:http://www.cplusplus.com/reference/ctime/time_t/。因此,它總是可以被轉換(可能有一些信息丟失)到一個'unsigned int'中。 – b4hand 2014-10-05 22:06:00

+0

@ b4hand我同意這篇文章太過保守了......儘管您引用的鏈接確實會說「可移植程序不應直接使用此類型的值,但始終要依靠對標準庫元素的調用來將它們轉換爲便攜類型「。 – amdn 2014-10-05 22:43:43

+1

如果您關心跨平臺轉換的*行爲*或結果相同,那麼它是不可移植的,但僅僅依靠轉換存在是完全可移植的,因此使代碼本身有效。 – b4hand 2014-10-06 02:28:46