从任何内存地址读取UInt32最有效的方法?

从C ++中的任意内存地址读取UInt32值最有效的方法是什么? (假设Windows x86或Windows x64架构)

例如,考虑有一个指向内存某处的字节指针,该指针包含ints,string数据等的组合,全部混合在一起。 以下示例显示了从循环中读取该块中的各个字段。

typedef unsigned char* BytePtr; typedef unsigned int UInt32; ... BytePtr pCurrent = ...; while ( *pCurrent != 0 ) { ... if ( *pCurrent == ... ) { UInt32 nValue = *( (UInt32*) ( pCurrent + 1 ) ); // line A ... } pCurrent += ...; } 

如果在A行, pPtr碰巧包含一个4字节alignment的地址,读取UInt32应该是一次读取内存。 如果pPtr包含一个不alignment的地址,我需要多于一个的内存循环,这会减慢代码的速度。 有没有更快的方式来读取非alignment地址的值?

我建议memcpy到您的循环内的类型的UInt32的临时。

这利用了一个事实,即在启用优化的情况下,编译器会将四个字节的memcpy内联,并具有其他一些优点:

  • 如果你在一个平台对齐的平台上(hpux,solaris sparc,…),你的代码不会陷入困境。
  • 在对齐很重要的平台上,可能需要进行地址检查以确定对齐方式,然后是常规对齐加载或4字节加载和位组。 你的编译器的memcpy很可能会这样做的最佳方式。
  • 如果你在一个允许不对齐访问的平台上,并且不会损害性能(x86,x64,powerpc,…),那么你几乎可以保证这样一个memcpy将是最便宜的方法访问。
  • 如果你的内存最初是一个指向其他数据结构的指针,那么你的代码可能是未定义的,因为有别名问题,因为你正在转换为另一种类型并且取消引用该转换。 由于锯齿相关的优化问题而导致的运行时间问题非常难以追查! 假设你可以把它们弄清楚,在已经建立的代码中修复也是非常困难的,你可能不得不使用-fno-strict-aliasing或-qansialias这些难以理解的编译选项,这会严重限制编译器的优化能力。

你的代码是未定义的行为。

几乎所有唯一的“正确的”解决方案是只读取类型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; 

在这个例子中,你想要读取一个整数,唯一的办法是一个整数。 如果您希望它包含某个二进制表示,则需要将该数据复制到变量开头的地址。

让编译器做优化!

 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); }