2012-01-25 47 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:你假设编译器不会优化代码。 –