按位运算。这段代码安全且便携吗?

时间:2013-09-06 13:07:05

标签: c++

我需要计算表示为char数组的位集之间的汉明距离。这是一项核心操作,因此必须尽可能快。我有这样的事情:

const int N = 32; // 32 always

// returns the number of bits that are ones in a char
int countOnes_uchar8(unsigned char v);

// pa and pb point to arrays of N items
int hamming(const unsigned char *pa, const unsigned char *pb)
{
  int ret = 0;
  for(int i = 0; i < N; ++i, ++pa, ++pb)
  {
    ret += countOnes_uchar8(*pa ^ *pb);
  }
  return ret;
}

在分析之后,我注意到在int上运行的速度更快,所以我写道:

const int N = 32; // 32 always

// returns the number of bits that are ones in a int of 32 bits
int countOnes_int32(unsigned int v);

// pa and pb point to arrays of N items
int hamming(const unsigned char *pa, const unsigned char *pb)
{
  const unsigned int *qa = reinterpret_cast<const unsigned int*>(pa);
  const unsigned int *qb = reinterpret_cast<const unsigned int*>(pb);

  int ret = 0;
  for(int i = 0; i < N / sizeof(unsigned int); ++i, ++qa, ++qb)
  {
    ret += countOnes_int32(*qa ^ *qb);
  }
  return ret;
}

问题

1)从unsigned char *unsigned int *的投射安全吗?

2)我在32位机器上工作,但我希望代码可以在64位机器上运行。 sizeof(unsigned int)在两台机器中都返回4,或者在64位机器上是8吗?

3)如果sizeof(unsigned int)在64位机器中返回4,那么我怎样才能使用long long在64位类型上运行?

2 个答案:

答案 0 :(得分:11)

  

unsigned char *unsigned int *的投射安全吗?

正式地,它给出了未定义的行为。实际上,它将适用于任何平台,如果指针适当地对齐unsigned int。在某些平台上,如果对齐错误,它可能会失败或表现不佳。

  

sizeof(unsigned int)在两台机器中都返回4,或者在64位机器上是8吗?

这取决于。有些平台有64位int,有些平台有32位。无论平台如何,使用uint64_t都可能是有意义的;在32位平台上,您将有效地展开循环(每次迭代处理两个32位值),这可能会有适度的改进。

  

如何使用long long

对64位类型进行操作?

uint64_t,如果您有C ++ 11或C99库。 long long至少为64位,但在2011年之前的实现中可能不存在。

答案 1 :(得分:2)

1)不,它不安全/便携,它是未定义的行为。有些系统char大于一个字节,并且无法保证char指针正确对齐。

2)sizeof(int)理论上可能是64位机器上的任何东西。在实践中,它将是4或8。

3)long long 最有可能 64位,但也无法保证。如果您需要保证,请使用uint64_t。但是,对于您的特定算法,我不明白为什么sizeof()数据块很重要。

考虑使用stdint.h中的类型,它们更适合于可移植代码。而不是char,int或long long,使用uint_fast8_t。这将让编译器以可移植的方式为您选择最快的整数。

作为旁注,您应该考虑将“countOnes”实现为查找表,工作在4位,8位或32位,具体取决于系统的最佳选择。这将增加程序大小,但会缩短执行时间。也许尝试实现某种形式的自适应查找表,这取决于sizeof(uint_fast8_t)