2010-05-28 99 views
5

我目前在一個代碼庫中工作,其中IPv4地址表示爲指向u_int8的指針。等於運算符來實現這樣的:字符數組的快速比較?

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return (*(u_int32*) this->myBytes == *(u_int32*) inAddress); 
} 

這可能是禁食的解決方案,但它會導致GCC編譯器警告:

ipv4address.cpp:65: warning: dereferencing type-punned pointer will break strict-aliasing rules 

我怎樣才能正確地改寫比較沒有打破嚴格走樣規則並且不會失去性能點?

我可以選擇是使用memcmp或該宏認爲:

#define IS_EQUAL(a, b) \ 
    (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) 

我想的是,宏是最快的解決方案。

你有什麼建議?

更新
我剛纔讀這也解釋了編譯器(Visual Studio中,但或許也GCC)如何優化!memcmp(..)來電文章Squeezing performance out of memcmp usage

+1

您是否嘗試了不同的選項並對它們進行基準測試,以查看哪一個確實是最快的? – 2010-05-28 14:45:10

+0

@尼克邁爾,還沒有,但這是一個很好的建議。 – StackedCrooked 2010-05-28 15:10:02

回答

10

我會去memcmp()

  1. 更便攜
  2. 我平時儘量不要比我的編譯器/語言智能。您試圖比較內存內容和(取決於編譯器選項)memcmp()的實現應該是最有效的方法。

還認爲,如果你的編譯器不內聯memcmp(),你將遭受函數上下文切換

是否確實需要優化是很辛苦?你是否已經檢查過你的程序大部分時間都在做這種類型的操作?

+2

是的,'std :: memcmp()'是std lib用於比較內置數組的比較。從我+1。如果分析顯示某個架構上的速度太慢,則可以隨時返回並更改它。不過,我懷疑它。 – sbi 2010-05-28 14:45:00

+1

作爲一名好的<插入語言>程序員意味着要知道如何使用標準工具箱中提供的工具。另外,不成熟的優化是所有邪惡的根源。我知道這些聽起來像教科書的反應,但它們都是如此重要和未充分利用,即使是我們有時最好的,他們是值得重複...再次...並再次... – corsiKa 2010-05-28 14:47:45

+1

比較IP地址' uint8'的uint8'也是便攜式的。少量的比較通常比庫函數調用更有效;儘管只有分析或彙編語言列表才能顯示證據。 – 2010-05-28 16:43:03

3

你從GCC得到錯誤的原因是任何長度超過1個字節的東西都喜歡與對象大小倍數的地址對齊。一個32位整數喜歡在32位邊界上開始。 A變量(有符號,無符號或無符號)可以位於任何字節邊界上,例如3,對於處理器的32位提取而言,該變量不起作用。

在你的情況下,對於4個字節(32位),調用memcmp的開銷可能比實際比較字節的代碼更多。

試試這個:

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return myBytes[0] == inAddress[0] 
     && myBytes[1] == inAddress[1] 
     && myBytes[2] == inAddress[2] 
     && myBytes[3] == inAddress[3]; 
} 

尋找母親,成員函數的代碼,而無需使用this->

至於效率,這個代碼很可能在撥打memcpy和從它執行的返回(不執行memcpy的內容)的同時執行。這是假設memcpy未內聯。瞭解如何爲通用和大型案例編寫編譯器庫,我懷疑這個代碼比內嵌版本memcpy更小更快。雖然證明是打印兩個版本的彙編列表並進行比較。

編輯:
注:聲明執行內聯或將代碼中的類聲明,會比定義一個危險的宏更好。它會更安全幷包含相同數量的代碼。我喜歡內聯方法版本,因爲它更易讀,更易於維護。