【问题标题】:shift count >= width of type and macros vs inline function移位计数> =类型和宏的宽度与内联函数
【发布时间】:2013-04-10 10:51:11
【问题描述】:

我正在处理一些位操作,但在宏与内联函数中的同一行代码中遇到了奇怪的不同输出。该函数从N-th 位置返回具有L 活动位的64 位掩码:(~0<<N) - (~0<<(N+L))。有人可以告诉我输出不同的原因吗?

#include <iostream>
#include <bitset>
using namespace std;

#define ONES (~0UL)

#define MASK(from_bit, nbits) \
  (ONES << (from_bit)) - (ONES << ((from_bit) + (nbits)))

inline unsigned long int mask(size_t from_bit, size_t nbits) {
  return (ONES << from_bit) - (ONES << (from_bit + nbits));
}

int main(int argc, char **argv) {
  cout << "using #define:         " << bitset<64>(MASK(63, 3)) << endl;
  cout << "using inline function: " << bitset<64>(mask(63, 3)) << endl;
  return 0;
}

输出:

$ g++ -o test main.cc
main.cc: In function 'int main(int, char**)':
main.cc:15: warning: left shift count >= width of type
$ ./test
using #define:         1000000000000000000000000000000000000000000000000000000000000000
using inline function: 1000000000000000000000000000000000000000000000000000000000000100
                                                                              ------^

使用-O3 选项编译:

$ g++ -O3 -o test2 main2.cc
main.cc: In function 'int main(int, char**)':
main.cc:15: warning: left shift count >= width of type
$ ./test2
using #define:         1000000000000000000000000000000000000000000000000000000000000000
using inline function: 0000000000000000000000000000000000000000000000000000000000000000
                 ------^

编译器信息:

$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)

【问题讨论】:

  • 可能是因为您将(最多)64 位类型移动超过 64 位,从而导致未定义的行为。注意你的编译器警告!
  • 所以溢出左移不会像我想的那样自动删除位...

标签: c++ macros inline


【解决方案1】:

您不应忽略编译器警告。它告诉你有问题。

合法地,您只能移动比整数类型中的位数更少的位置。

这行得通:

#include <iostream>
#include <bitset>
using namespace std;

#define ONES (~0ULL)

#define MASK(from_bit, nbits) \
  (ONES << (from_bit)) - (ONES << (from_bit) << (nbits))

inline unsigned long long mask(unsigned from_bit, unsigned nbits) {
  return (ONES << from_bit) - (ONES << from_bit << nbits);
}

int main(int argc, char **argv) {
  cout << "using #define:         " << bitset<64>(MASK(63, 3)) << endl;
  cout << "using inline function: " << bitset<64>(mask(63, 3)) << endl;
  return 0;
}

输出(ideone):

using #define:         1000000000000000000000000000000000000000000000000000000000000000
using inline function: 1000000000000000000000000000000000000000000000000000000000000000

【讨论】:

  • 谢谢,ONES &lt;&lt; from_bit &lt;&lt; nbits 部分的好技巧。我什至不必使用ULL 作为掩码。
  • 我将 UL 更改为 ULLunsigned long 更改为 unsigned long long 以确保类型中有 64 位。 unsigned long 至少为 32 位,即可以小于 64。unsigned long long 保证为 64 位或更大。此外,班次数量很少,不需要为他们使用任何可能大于unsigned int 的东西(例如longsize_t)。
【解决方案2】:

您的编译器警告说明了这一点。

您的移位量 (from_bit + nbits) 大于您使用的类型的大小。

而宏和函数的区别在于,前者没有类型检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    相关资源
    最近更新 更多