C++ 位操作在我的系统上编译时没有错误,但 Godbolt 编译器给出 warning/errors
C++ bit manipulation compiles with no errors on my system but godbolt compilers give warning/errors
编辑:Godbolt link 例如 here!
所以我有这个例子来展示我制作的宏及其用例:
#include <bitset>
#include <iostream>
#define bit_mask(size, offset) (~(~0 << size) << offset)
#define bit_masked_set(dst, src, mask, offset) (dst = (dst & ~mask) | (src << offset))
#define bit_masked_get(src, mask, offset) ((src & mask) >> offset)
constexpr unsigned front_mask = bit_mask(16, 16);
constexpr unsigned back_mask = bit_mask(16, 0);
int main() {
std::cout << std::bitset<32>(front_mask) << " = front_mask (bit_mask(16, 16))\n";
std::cout << std::bitset<32>(back_mask) << " = back_mask (bit_mask(16, 0))\n\n";
unsigned value = 0;
std::cout << std::bitset<32>(value) << " = value (initial)\n\n";
bit_masked_set(value, 1, front_mask, 16);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";
bit_masked_set(value, 1, back_mask, 0);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";
std::cout << std::bitset<32>(value) << " = value (final)\n";
}
输出:
11111111111111110000000000000000 = front_mask (bit_mask(16, 16))
00000000000000001111111111111111 = back_mask (bit_mask(16, 0))
00000000000000000000000000000000 = value (initial)
00000000000000010000000000000000 = value (after bit_masked_set(value, 1, front_mask, 16))
00000000000000010000000000000001 = value (after bit_masked_set(value, 1, back_mask, 0))
00000000000000010000000000000001 = value (final)
我正在使用 Visual Studio 2017 和 -Wall -c++17,对此我很满意。但我注意到,当我将它粘贴到 godbolt 网站时,gcc/clang/etc 会针对以下内容发出警告和/或错误:
error: constexpr variable 'front_mask' must be initialized by a constant expression
...
error: left operand of shift expression '(-1 << 16)' is negative [-fpermissive]
...
etc
因为这些预处理器宏使用分配给已知数据类型的常量值,所以这不应该成为问题。
编辑2:
我更多地尝试这个,发现将我的 bit_mask
宏更改为:
#define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset)
似乎解决了问题。我不是 100% 确定我是否需要额外的 long long
但我假设它不会造成伤害,它会更灵活。
编辑 3:
将代码从宏显着更新为简单结构:
#include <bitset>
#include <iostream>
#include <type_traits>
struct BitMask {
using Mask_Type = unsigned long long;
Mask_Type mask;
unsigned offset;
constexpr BitMask(unsigned size, unsigned offset) :
mask{~((Mask_Type)~0 << size) << offset},
offset{offset} {
}
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
constexpr T set_bits(T& dst, T src) const {
return dst = (dst & ~mask) | (src << offset);
}
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
constexpr T get_bits(T src) const {
return (src & mask) >> offset;
}
};
constexpr BitMask front_mask = BitMask(16, 16);
constexpr BitMask back_mask = BitMask(16, 0);
int main() {
std::cout << std::bitset<32>(front_mask.mask) << " = front_mask (bit_mask(16, 16))\n";
std::cout << std::bitset<32>(back_mask.mask) << " = back_mask (bit_mask(16, 0))\n\n";
unsigned value = 0;
std::cout << std::bitset<32>(value) << " = value (initial)\n\n";
front_mask.set_bits(value, 1U);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";
back_mask.set_bits(value, 1U);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";
std::cout << std::bitset<32>(value) << " = value (final)\n";
}
既然 #define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset)
似乎解决了问题,我会将其标记为已回答。如果有人发帖说这不是正确的解决方案,并且他们提供了不同的东西,我会接受他们的回答,前提是它有效。
编辑:Godbolt link 例如 here!
所以我有这个例子来展示我制作的宏及其用例:
#include <bitset>
#include <iostream>
#define bit_mask(size, offset) (~(~0 << size) << offset)
#define bit_masked_set(dst, src, mask, offset) (dst = (dst & ~mask) | (src << offset))
#define bit_masked_get(src, mask, offset) ((src & mask) >> offset)
constexpr unsigned front_mask = bit_mask(16, 16);
constexpr unsigned back_mask = bit_mask(16, 0);
int main() {
std::cout << std::bitset<32>(front_mask) << " = front_mask (bit_mask(16, 16))\n";
std::cout << std::bitset<32>(back_mask) << " = back_mask (bit_mask(16, 0))\n\n";
unsigned value = 0;
std::cout << std::bitset<32>(value) << " = value (initial)\n\n";
bit_masked_set(value, 1, front_mask, 16);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";
bit_masked_set(value, 1, back_mask, 0);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";
std::cout << std::bitset<32>(value) << " = value (final)\n";
}
输出:
11111111111111110000000000000000 = front_mask (bit_mask(16, 16))
00000000000000001111111111111111 = back_mask (bit_mask(16, 0))
00000000000000000000000000000000 = value (initial)
00000000000000010000000000000000 = value (after bit_masked_set(value, 1, front_mask, 16))
00000000000000010000000000000001 = value (after bit_masked_set(value, 1, back_mask, 0))
00000000000000010000000000000001 = value (final)
我正在使用 Visual Studio 2017 和 -Wall -c++17,对此我很满意。但我注意到,当我将它粘贴到 godbolt 网站时,gcc/clang/etc 会针对以下内容发出警告和/或错误:
error: constexpr variable 'front_mask' must be initialized by a constant expression
...
error: left operand of shift expression '(-1 << 16)' is negative [-fpermissive]
...
etc
因为这些预处理器宏使用分配给已知数据类型的常量值,所以这不应该成为问题。
编辑2:
我更多地尝试这个,发现将我的 bit_mask
宏更改为:
#define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset)
似乎解决了问题。我不是 100% 确定我是否需要额外的 long long
但我假设它不会造成伤害,它会更灵活。
编辑 3:
将代码从宏显着更新为简单结构:
#include <bitset>
#include <iostream>
#include <type_traits>
struct BitMask {
using Mask_Type = unsigned long long;
Mask_Type mask;
unsigned offset;
constexpr BitMask(unsigned size, unsigned offset) :
mask{~((Mask_Type)~0 << size) << offset},
offset{offset} {
}
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
constexpr T set_bits(T& dst, T src) const {
return dst = (dst & ~mask) | (src << offset);
}
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
constexpr T get_bits(T src) const {
return (src & mask) >> offset;
}
};
constexpr BitMask front_mask = BitMask(16, 16);
constexpr BitMask back_mask = BitMask(16, 0);
int main() {
std::cout << std::bitset<32>(front_mask.mask) << " = front_mask (bit_mask(16, 16))\n";
std::cout << std::bitset<32>(back_mask.mask) << " = back_mask (bit_mask(16, 0))\n\n";
unsigned value = 0;
std::cout << std::bitset<32>(value) << " = value (initial)\n\n";
front_mask.set_bits(value, 1U);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";
back_mask.set_bits(value, 1U);
std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";
std::cout << std::bitset<32>(value) << " = value (final)\n";
}
既然 #define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset)
似乎解决了问题,我会将其标记为已回答。如果有人发帖说这不是正确的解决方案,并且他们提供了不同的东西,我会接受他们的回答,前提是它有效。