在代码中,我有时会看到人们以十六进制格式指定常量,如下所示:
const int has_nukes = 0x0001;
const int has_bio_weapons = 0x0002;
const int has_chem_weapons = 0x0004;
// ...
int arsenal = has_nukes | has_bio_weapons | has_chem_weapons; // all of them
if(arsenal &= has_bio_weapons){
std::cout << "BIO!!"
}
但是我在这里使用十六进制格式没有意义。有没有办法直接用二进制文件做?像这样:
const int has_nukes = 0b00000000000000000000000000000001;
const int has_bio_weapons = 0b00000000000000000000000000000010;
const int has_chem_weapons = 0b00000000000000000000000000000100;
// ...
我知道C / C ++编译器不会编译它,但必须有一个解决方法吗?是否可以在Java等其他语言中使用?
答案 0 :(得分:62)
在C ++ 14中,您将能够使用以下语法的二进制文字:
0b010101010 /* more zeros and ones */
此功能已在最新的clang
和gcc
中实施。如果您使用-std=c++1y
选项运行这些编译器,则可以尝试使用它。
答案 1 :(得分:60)
我使用位移操作符:
const int has_nukes = 1<<0;
const int has_bio_weapons = 1<<1;
const int has_chem_weapons = 1<<2;
// ...
int dangerous_mask = has_nukes | has_bio_weapons | has_chem_weapons;
bool is_dangerous = (country->flags & dangerous_mask) == dangerous_mask;
甚至比0的泛滥更好。
答案 2 :(得分:34)
顺便说一句,下一个C ++版本将支持用户定义的文字。它们已经包含在工作草案中。这允许那种东西(让我希望我没有太多的错误):
template<char... digits>
constexpr int operator "" _b() {
return conv2bin<digits...>::value;
}
int main() {
int const v = 110110110_b;
}
conv2bin
将是这样的模板:
template<char... digits>
struct conv2bin;
template<char high, char... digits>
struct conv2bin<high, digits...> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0') * (1 << sizeof...(digits)) +
conv2bin<digits...>::value;
};
template<char high>
struct conv2bin<high> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0');
};
嗯,我们得到的是二进制文字,它们已经在编译时完全评估,因为上面的“constexpr”。以上使用硬编码的int返回类型。我想甚至可以使它依赖于二进制字符串的长度。对于任何感兴趣的人,它都使用以下功能:
实际上,当前的GCC主干already实现了可变参数模板和静态断言。我们希望它能尽快支持其他两个。我认为C ++ 1x将会震撼整个房子。
答案 3 :(得分:15)
C ++标准库是你的朋友:
#include <bitset>
const std::bitset <32> has_nukes( "00000000000000000000000000000001" );
答案 4 :(得分:13)
您可以使用&lt;&lt;如果你愿意的话。
int hasNukes = 1;
int hasBioWeapons = 1 << 1;
int hasChemWeapons = 1 << 2;
答案 5 :(得分:12)
自4.3以来,GCC支持二进制常量作为扩展。请参阅announcement(请参阅“新语言和语言特定改进”部分)。
答案 6 :(得分:9)
This discussion可能很有趣 ......可能已经存在,因为链接已经死了。它描述了一种类似于其他答案的基于模板的方法。
还有一个名为BOOST_BINARY的东西。
答案 7 :(得分:9)
您想要的术语是二进制文字
Ruby has them使用您提供的语法。
一种替代方法是定义帮助宏以便为您进行转换。我在http://bytes.com/groups/c/219656-literal-binary
找到了以下代码/* Binary constant generator macro
* By Tom Torfs - donated to the public domain
*/
/* All macro's evaluate to compile-time constants */
/* *** helper macros *** */
/* turn a numeric literal into a hex constant
* (avoids problems with leading zeroes)
* 8-bit constants max value 0x11111111, always fits in unsigned long
*/
#define HEX_(n) 0x##n##LU
/* 8-bit conversion function */
#define B8_(x) ((x & 0x0000000FLU) ? 1:0) \
| ((x & 0x000000F0LU) ? 2:0) \
| ((x & 0x00000F00LU) ? 4:0) \
| ((x & 0x0000F000LU) ? 8:0) \
| ((x & 0x000F0000LU) ? 16:0) \
| ((x & 0x00F00000LU) ? 32:0) \
| ((x & 0x0F000000LU) ? 64:0) \
| ((x & 0xF0000000LU) ? 128:0)
/* *** user macros *** /
/* for upto 8-bit binary constants */
#define B8(d) ((unsigned char) B8_(HEX_(d)))
/* for upto 16-bit binary constants, MSB first */
#define B16(dmsb, dlsb) (((unsigned short) B8(dmsb) << 8) \
| B8(dlsb))
/* for upto 32-bit binary constants, MSB first */
#define B32(dmsb, db2, db3, dlsb) (((unsigned long) B8(dmsb) << 24) \
| ((unsigned long) B8( db2) << 16) \
| ((unsigned long) B8( db3) << 8) \
| B8(dlsb))
/* Sample usage:
* B8(01010101) = 85
* B16(10101010,01010101) = 43605
* B32(10000000,11111111,10101010,01010101) = 2164238933
*/
答案 8 :(得分:4)
C ++的下一个版本C ++ 0x将引入user defined literals。我不确定二进制数字是否会成为标准的一部分,但最糟糕的是你可以自己启用它:
int operator "" _B(int i);
assert( 1010_B == 10);
答案 9 :(得分:4)
我写这样的二进制文字:
const int has_nukes = 0x0001;
const int has_bio_weapons = 0x0002;
const int has_chem_weapons = 0x0004;
它比您建议的符号更紧凑,更易于阅读。例如:
const int upper_bit = 0b0001000000000000000;
与
const int upper_bit = 0x04000;
您是否注意到二进制版本不是4位的偶数倍?你认为它是0x10000吗?
对于人而言,十六进制或八进制比二进制更容易练习。而且,在我看来,使用移位运算符更容易阅读。但我会承认,我多年的汇编语言工作可能会让我偏向于这一点。
答案 10 :(得分:2)
遗憾的是,Java也不支持二进制文字。但是,它有 enums ,可与EnumSet
一起使用。 EnumSet
在内部用位字段表示枚举值,并提供用于操作这些标志的Set
接口。
或者,您可以在定义值时使用位偏移(十进制):
const int HAS_NUKES = 0x1 << 0;
const int HAS_BIO_WEAPONS = 0x1 << 1;
const int HAS_CHEM_WEAPONS = 0x1 << 2;
答案 11 :(得分:1)
我同意有一个二进制文字选项是有用的,它们存在于许多编程语言中。在C中,我决定使用这样的宏:
#define bitseq(a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
(a31|a30<< 1|a29<< 2|a28<< 3|a27<< 4|a26<< 5|a25<< 6|a24<< 7| \
a23<< 8|a22<< 9|a21<<10|a20<<11|a19<<12|a18<<13|a17<<14|a16<<15| \
a15<<16|a14<<17|a13<<18|a12<<19|a11<<20|a10<<21|a09<<22|a08<<23| \
a07<<24|a06<<25|a05<<26|a04<<27|a03<<28|a02<<29|a01<<30|(unsigned)a00<<31)
用法非常简单=)
答案 12 :(得分:1)
如果你想使用bitset,auto,variadic模板,用户定义的文字,static_assert,constexpr,和 noexcept试试这个:
template<char... Bits>
struct __checkbits
{
static const bool valid = false;
};
template<char High, char... Bits>
struct __checkbits<High, Bits...>
{
static const bool valid = (High == '0' || High == '1')
&& __checkbits<Bits...>::valid;
};
template<char High>
struct __checkbits<High>
{
static const bool valid = (High == '0' || High == '1');
};
template<char... Bits>
inline constexpr std::bitset<sizeof...(Bits)>
operator"" bits() noexcept
{
static_assert(__checkbits<Bits...>::valid, "invalid digit in binary string");
return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
}
像这样使用:
int
main()
{
auto bits = 0101010101010101010101010101010101010101010101010101010101010101bits;
std::cout << bits << std::endl;
std::cout << "size = " << bits.size() << std::endl;
std::cout << "count = " << bits.count() << std::endl;
std::cout << "value = " << bits.to_ullong() << std::endl;
// This triggers the static_assert at compile-time.
auto badbits = 2101010101010101010101010101010101010101010101010101010101010101bits;
// This throws at run-time.
std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101bits");
}
感谢@ johannes-schaub-litb
答案 13 :(得分:1)
另一种方法:
template<unsigned int N>
class b
{
public:
static unsigned int const x = N;
typedef b_<0> _0000;
typedef b_<1> _0001;
typedef b_<2> _0010;
typedef b_<3> _0011;
typedef b_<4> _0100;
typedef b_<5> _0101;
typedef b_<6> _0110;
typedef b_<7> _0111;
typedef b_<8> _1000;
typedef b_<9> _1001;
typedef b_<10> _1010;
typedef b_<11> _1011;
typedef b_<12> _1100;
typedef b_<13> _1101;
typedef b_<14> _1110;
typedef b_<15> _1111;
private:
template<unsigned int N2>
struct b_: public b<N << 4 | N2> {};
};
typedef b<0> _0000;
typedef b<1> _0001;
typedef b<2> _0010;
typedef b<3> _0011;
typedef b<4> _0100;
typedef b<5> _0101;
typedef b<6> _0110;
typedef b<7> _0111;
typedef b<8> _1000;
typedef b<9> _1001;
typedef b<10> _1010;
typedef b<11> _1011;
typedef b<12> _1100;
typedef b<13> _1101;
typedef b<14> _1110;
typedef b<15> _1111;
用法:
std::cout << _1101::_1001::_1101::_1101::x;
答案 14 :(得分:1)
暂且不说:
特别是如果你正在处理一个大集合,而不是通过编写一系列移位量的[次要]心理努力,你可以使每个常量取决于先前定义的常量:
const int has_nukes = 1;
const int has_bio_weapons = has_nukes << 1;
const int has_chem_weapons = has_bio_weapons << 1;
const int has_nunchuks = has_chem_weapons << 1;
// ...
看起来有点多余,但它不太容易出错。此外,您只需在中间插入一个新常量,而不必触及除紧随其后的任何其他行:
const int has_nukes = 1;
const int has_gravity_gun = has_nukes << 1; // added
const int has_bio_weapons = has_gravity_gun << 1; // changed
const int has_chem_weapons = has_bio_weapons << 1; // unaffected from here on
const int has_nunchuks = has_chem_weapons << 1;
// ...
比较:
const int has_nukes = 1 << 0;
const int has_bio_weapons = 1 << 1;
const int has_chem_weapons = 1 << 2;
const int has_nunchuks = 1 << 3;
// ...
const int has_scimatar = 1 << 28;
const int has_rapier = 1 << 28; // good luck spotting this typo!
const int has_katana = 1 << 30;
和
const int has_nukes = 1 << 0;
const int has_gravity_gun = 1 << 1; // added
const int has_bio_weapons = 1 << 2; // changed
const int has_chem_weapons = 1 << 3; // changed
const int has_nunchuks = 1 << 4; // changed
// ... // changed all the way
const int has_scimatar = 1 << 29; // changed *sigh*
const int has_rapier = 1 << 30; // changed *sigh*
const int has_katana = 1 << 31; // changed *sigh*
除此之外,我可能同样难以发现这样的拼写错误:
const int has_nukes = 1;
const int has_gravity_gun = has_nukes << 1;
const int has_bio_weapons = has_gravity_gun << 1;
const int has_chem_weapons = has_gravity_gun << 1; // oops!
const int has_nunchuks = has_chem_weapons << 1;
所以,我认为这种级联语法的主要优点是处理常量的插入和删除。
答案 15 :(得分:1)
C ++中的文字二进制常量没有十六进制和八进制的语法。最接近你想要做的事情可能是学习和使用bitset。
答案 16 :(得分:1)
你能做到的一个有点可怕的方法就是生成一个包含很多#defines的.h文件......
#define b00000000 0
#define b00000001 1
#define b00000010 2
#define b00000011 3
#define b00000100 4
等。 这可能对8位数有意义,但可能不适用于16位或更大。
或者,这样做(类似于Zach Scrivena的回答):
#define bit(x) (1<<x)
int HAS_NUKES = bit(HAS_NUKES_OFFSET);
int HAS_BIO_WEAPONS = bit(HAS_BIO_WEAPONS_OFFSET);