2012-02-28 66 views
-1

哪兩個更快:?作業vs mempcy - 在這種情況下速度會更快

1.

char* _pos ..; 
short value = ..; 

*((short*)_pos = va; 

2.

char* _pos ..; 
short value = ..; 

memcpy(_pos, &value, sizeof(short)); 
+1

1是更快的和危險的,2是比較慢(它調用,即使它可以被編譯器優化的函數)和也是危險的。 – vulkanino 2012-02-28 10:00:37

+13

是否將程序分配爲'short'的瓶頸? – 2012-02-28 10:02:22

+0

我的猜測是他正在創建一個二進制blob的消息數據,這將要做很多次打包和解壓縮消息。 – CashCow 2012-02-28 10:24:22

回答

8

與所有「哪個更快?」問題,你應該基準它看看你自己。如果它很重要,然後問爲什麼,並選擇你想要的。

在任何情況下,你的第一個例子是技術上未定義的行爲,因爲你違反了嚴格的鋸齒。所以如果你必須選擇沒有基準的話,就去找第二個。


要回答實際問題,速度更快可能取決於對齊pos。如果它正確對齊,那麼1可能會更快。如果不是,那麼2可能會更快,這取決於編譯器如何對其進行優化。 (1如果硬件不支持錯位訪問,甚至可能會崩潰。)

但是,這是所有的猜測工作。你確實需要對它進行基準測試以確定。
最起碼,你應該看看編譯的程序集:

:  *(short *)_pos = value; 

mov WORD PTR [rcx], dx 

:  memcpy(_pos, &value, sizeof(short)); 

mov WORD PTR [rcx], dx 

在這種情況下(MSVC)顯示了默認優化完全相同的組件。所以你可以預期性能是一樣的。

2

編譯器可能會實現它們都以同樣的方式。
如果它天真地做,分配會更快。

對於任何實際的目的,他們都將很快完成,你不必擔心。 (

另請注意,您可能有對齊問題s(_pos可能未對齊2個字節,這可能會在某些處理器上崩潰),並輸入雙擊問題(編譯器可能會假定指向的內容未更改,因爲你使用short *編寫)。

0

重要嗎?可能是第一種情況會爲您節省一些週期(取決於編譯器的複雜性和優化)。但是值得一提的可讀性和可維護性呢?

由於過早優化引入了許多錯誤。你應該首先確定瓶頸,如果這個任務是瓶頸 - 基準每個選項(考慮到其他人已經提到的對齊和其他問題)。

0

問題是依賴於實現。在實踐中,除了複製sizeof(short)字節之外什麼都不做,如果其中一個會變慢,它將是memcpy。對於相當大的數據集,如果速度更快,通常會是memcpy。

如前所述,#1調用未定義的行爲。

我們可以看到,簡單的賦值當然比兩者更易於讀寫,並且容易出錯。清晰性和正確性應該是第一位的,即使在性能關鍵領域也是如此,理由很簡單,因爲優化正確的代碼比修復優化的不正確的代碼更容易。如果這真的是一個C++問題,那麼需要這樣的代碼(對類型系統進行X射線渲染和複製位的casts或memcpy)是非常非常罕見的。

4

隨着gcc-O1或更高的優化級別,下面的兩個函數編譯成一模一樣的機器代碼在x86:

void foo(char *_pos, short value) 
{ 
     memcpy(_pos, &value, sizeof(short)); 
} 

void bar(char *_pos, short value) 
{ 
     *(short *)_pos = value; 
} 
0

如果你確信不會有對齊問題,你真的覺得這是一個瓶頸的情況,然後繼續前進,並做第一個。

如果你不高興,然後調用memcpy的做一些事情,如:

*pos = static_cast<char>(value & 0xff); 
*(pos+1) = static_cast<char>(value >> 8); 

但如果你要做到這一點,然後使用無符號值。

上述代碼可確保您獲得小端。 (如果你想要big-endian,顯然會顛倒作業的順序)。如果數據是作爲某種二進制blob傳遞的,也就是我假設你想要創建的二進制blob,你可能需要一致的endian-ness。

如果您想創建二進制blob,您可能希望使用類似google協議緩衝區的內容。還有boost :: serialize,其中包括二進制序列化。

0

可避免破壞別名規則,並利用共用調用函數:

union { 
    char* c; 
    short* s; 
} _pos; 

short value = ... 

_pos->s = value;