2012-01-25 96 views
3

從C++中的任意內存地址讀取UInt32值的最有效方法是什麼? (假設Windows x86或Windows x64體系結構)。從任何內存地址讀取UInt32的最有效方法?

例如,考慮將指向內存某處的字節指針指向包含ints,string數據等所有混合在一起的block。以下示例顯示了從循環中讀取此塊中的各個字段。

typedef unsigned char* BytePtr; 
typedef unsigned int UInt32; 

... 

BytePtr pCurrent = ...; 

while (*pCurrent != 0) 
{ 
    ... 

    if (*pCurrent == ...) 
    { 
     UInt32 nValue = *((UInt32*) (pCurrent + 1)); // line A 

     ... 
    } 

    pCurrent += ...; 
} 

如果在線路ApPtr恰好包含一個4字節對齊地址時,讀取該UInt32的應是一個單一的存儲器中讀出。如果pPtr包含一個不對齊的地址,我需要多於一個的內存週期,這會減慢代碼的速度。有沒有更快的方法來讀取非對齊地址的值?

回答

3

我建議將memcpy插入循環中的臨時類型UInt32。

這需要一個事實,即一個四個字節的memcpy將由編譯器在啓用優化的建築物時被內聯優勢,並有一些其他的好處:

  • 如果你是在一個平臺上,其中對準事項( hpux,solaris sparc,...)你的代碼不會陷入困境。
  • 在一個平臺,定位的問題有可能是值得做比對的地址進行檢查,然後有規律排列的負載的一個或一組4級字節的負載和位口服補液鹽。你的編譯器的memcpy很可能會這樣做的最佳方式。
  • 如果你是哪裏不對齊訪問是允許的,不損害性能(X86,X64的PowerPC,...),你幾乎保證的廣告,這樣的memcpy的,然後將是最便宜的方式在一個平臺上做這個訪問。
  • 如果你的內存最初是一個指針到一些其他的數據結構,你的代碼可能會因爲走樣的問題不確定,因爲你是鑄造爲另一種類型,並提領該演員。由於混疊相關優化問題導致的運行時問題非常難以追查!假設你可以把它們弄清楚,修復在已經建立的代碼中也很難,你可能不得不使用模糊的編譯選項,如-fno-strict-aliasing或-qansialias,這可能顯着限制編譯器的優化能力。
+0

謝謝 - 我必須承認,我不知道嚴格的鋸齒規則。這也解釋了其他答案。我使用的是VC++和x86/x64,所以在這種情況下,可移植性並不是問題。由於其他原因,大部分代碼都與硬件有關。 xxbbcc

3

你的代碼是未定義的行爲。

幾乎是唯一「正確」的解決辦法是隻讀的東西作爲一種T如果一種T,如下所示:

uint32_t n; 
char * p = point_me_to_random_memory(); 

std::copy(p, p + 4, reinterpret_cast<char*>(&n)); 

std::cout << "The value is: " << n << std::endl; 

在這個例子中,你想讀的整數,唯一的辦法就是有一個整數。如果您希望它包含某個二進制表示,則需要將該數據複製到從變量開始處開始的地址。

+0

到底什麼是不確定的關於我的代碼?它讀取一串字節並基於某些字節,它知道後面有一個整數。除非我忽略了一些東西,否則你的例子與我的問題無關。 – xxbbcc

+0

根據C++標準對實現的最低要求,它是未定義的行爲,但在Windows x86和x64上它是可行的。 –

+0

@xxbbcc:您的Line A上最左邊的'*'會觸發未定義的行爲,因爲您正在取消引用的內容實際上不是指向所宣傳類型的指針。 –

0

讓編譯器的優化!

UInt32 ReadU32(unsigned char *ptr) 
{ 
    return static_cast<UInt32>(ptr[0]) | 
      (static_cast<UInt32>(ptr[1])<<8) | 
      (static_cast<UInt32>(ptr[2])<<16) | 
      (static_cast<UInt32>(ptr[3])<<24); 
} 
+0

我不認爲你需要在那裏演員。換擋操作已經將所有類型都推廣到了我認爲合適的大型車型。另外,你的答案真的是「這個字節流在解釋爲小端整數時意味着什麼」的問題。 :-) –

+0

你爲什麼認爲這樣更快? 'pCurrent'中的地址是動態的,並且隨着數據的讀取而變化。在我看來,您的示例執行4次內存讀取,然後將這些值與偏移一起進行或運算 - 這似乎比針對非對齊讀取發生的額外內存提取要慢。 – xxbbcc

+0

@xxbbcc:你假設編譯器不會優化代碼。 –