我需要处理一个二进制数。
我尝试写了以下代码:
const char x = 00010000;
但这并没有起作用。
我知道可以使用一个十六进制数,它具有与00010000
相同的值,但我想知道在C++中是否有一种二进制数类型,如果没有,是否有其他解决方案?int x = 0b11000;
在GCC 4.3中开始支持(请参阅https://gcc.gnu.org/gcc-4.3/changes.html),作为C语言家族的扩展(请参阅https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions)。但自从GCC 4.9以来,它已被认为是C++14的特性或扩展(请参阅Difference between GCC binary literals and C++14 ones?)。
在Visual Studio 2015 Preview中开始支持(请参阅https://www.visualstudio.com/news/vs2015-preview-vs#C++)。
template<unsigned long N>
struct bin {
enum { value = (N%10)+2*bin<N/10>::value };
} ;
template<>
struct bin<0> {
enum { value = 0 };
} ;
// ...
std::cout << bin<1000>::value << '\n';
字面值的最左边一位仍然必须是1,但尽管如此。
在等待C++0x到来时,你可以使用 BOOST_BINARY。相比模板实现,BOOST_BINARY
的优点是它也可以在 C 语言中使用(它完全是预处理器驱动的)。
如果要反过来(即以二进制形式输出数字),你可以使用不可移植的itoa
函数或自己实现。
不幸的是,在STL流中无法进行2进制格式化(因为setbase
只支持8、10和16进制),但是你可以使用std::string
版本的itoa
,或者使用更简洁但效率略低的std::bitset
。
#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
unsigned short b = BOOST_BINARY( 10010 );
char buf[sizeof(b)*8+1];
printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
cout << setfill('0') <<
"hex: " << hex << setw(4) << b << ", " <<
"dec: " << dec << b << ", " <<
"oct: " << oct << setw(6) << b << ", " <<
"bin: " << bitset< 16 >(b) << endl;
return 0;
}
得到:
hex: 0012, dec: 18, oct: 000022, bin: 10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010
同时阅读Herb Sutter的The String Formatters of Manor Farm,这篇文章讨论得非常有趣。
int main() { cout << bitset<8>(42); }
- Roger Patebitset
提示,不过在看到你的评论之前我已经纠正了关于 setbase
的错误。 - vladr一些编译器(通常是针对微控制器的编译器)实现了一个特殊功能,通过在数字前加上前缀"0b..."来识别字面二进制数,尽管大多数编译器(C/C++标准)没有这样的功能,如果是这种情况,这里是我的替代方案:
#define B_0000 0
#define B_0001 1
#define B_0010 2
#define B_0011 3
#define B_0100 4
#define B_0101 5
#define B_0110 6
#define B_0111 7
#define B_1000 8
#define B_1001 9
#define B_1010 a
#define B_1011 b
#define B_1100 c
#define B_1101 d
#define B_1110 e
#define B_1111 f
#define _B2H(bits) B_##bits
#define B2H(bits) _B2H(bits)
#define _HEX(n) 0x##n
#define HEX(n) _HEX(n)
#define _CCAT(a,b) a##b
#define CCAT(a,b) _CCAT(a,b)
#define BYTE(a,b) HEX( CCAT(B2H(a),B2H(b)) )
#define WORD(a,b,c,d) HEX( CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))) )
#define DWORD(a,b,c,d,e,f,g,h) HEX( CCAT(CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))),CCAT(CCAT(B2H(e),B2H(f)),CCAT(B2H(g),B2H(h)))) )
// Using example
char b = BYTE(0100,0001); // Equivalent to b = 65; or b = 'A'; or b = 0x41;
unsigned int w = WORD(1101,1111,0100,0011); // Equivalent to w = 57155; or w = 0xdf43;
unsigned long int dw = DWORD(1101,1111,0100,0011,1111,1101,0010,1000); //Equivalent to dw = 3745774888; or dw = 0xdf43fd28;
缺点(并不是很大的缺点):
优点:
模板+枚举解决方案仅适用于C++编译器
);"枚举解决方案"
的解析结果表达常量值,则通常会有早期的长度限制(通常为8位:0-255),相反,在编译器中允许更大的数字的"字面常量"限制;多个头文件
(在大多数情况下不易读和理解,并使项目变得不必要地混乱和扩展,例如使用"BOOST_BINARY()"
);B_0100
(而是使用 0100
)?例如在 char b = BYTE(0100,0001);
中。 - Peter Mortensen_B2H
预处理器函数会添加 B_。 - mxmlnkn这个帖子可能会有所帮助。
/* Helper macros */
#define HEX__(n) 0x##n##LU
#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 */
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
+ B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))
#include <stdio.h>
int main(void)
{
// 261, evaluated at compile-time
unsigned const number = B16(00000001,00000101);
printf("%d \n", number);
return 0;
}
成功了!(感谢Tom Torfs的所有贡献。)
##
预处理操作符会将标记粘贴在一起。因此,在这种情况下,如果调用 HEX__(10)
,它会扩展为 0x10LU
。 - James McNellisB16(ABCDEF89,01234567);
不过,非常聪明! - abelenky正如先前回答的那样,C标准没有直接编写二进制数字的方法。然而,有编译器扩展,显然 C++14 包括二进制的 0b
前缀。(请注意,此答案最初发布于2010年。)
一个常用的解决方法是包含一个带有辅助宏的头文件。另一个简单的选项是生成一个包含所有 8 位模式的宏定义的文件,例如:
#define B00000000 0
#define B00000001 1
#define B00000010 2
…
这样只会产生256个#define
,如果需要大于8位二进制常量,则可以将这些定义与移位和OR操作相结合,可能需要使用帮助宏(例如BIN16(B00000001,B00001010)
)。 (为每个16位,更不用说32位值编写单独的宏是不可行的。)
当然,缺点是这种语法需要编写所有前导零,但对于设置位标志和硬件寄存器内容等用途来说,这也可能使其更清晰。如需生成不具有此属性的类函数宏,请参见上面链接的bithacks.h
。
long long int
的所有宏定义,CPP需要读取多大的文件? - wilhelmtell##
连接来减少必要定义的数量。 - tangoal##
进行连接,我认为这需要一个语法,例如BIN16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
,但我认为这并不比答案中建议的BIN16(B00000001,B00001010)
更好。或者你有其他想法吗?(不可否认,具有智能自动完成功能的编辑器可能有助于前一种语法,并放置带有占位符的确切参数数量,尽管这不太容易手动输入,当您必须计数到16时。) - Arkku这里已经有其他答案对于C++过度工程化的心态进行了详细说明。以下是我尝试用C的“保持简单”的思路来解决:
unsigned char x = 0xF; // binary: 00001111
C语言没有原生的纯二进制数表示法。你最好使用八进制(例如07777
)或十六进制(例如0xfff
)。
您可以使用此问题中找到的函数来在C++中获取高达22位的二进制常量。以下是链接中适当编辑过的代码:
template< unsigned long long N >
struct binary
{
enum { value = (N % 8) + 2 * binary< N / 8 > :: value } ;
};
template<>
struct binary< 0 >
{
enum { value = 0 } ;
};
所以你可以这样做:binary<0101011011>::value
。
00010000
是八进制吗?(而且你的声明缺少类型。) - Keith Thompsonx
不是十六进制 (A
,B
,C
,D
,E
,F
),在二进制或十六进制数字前面写零不会影响它们中的任何一个,所以选择0b
作为二进制的前缀是否是任意的呢? - Aurelius0b
仅出现在C++14中)。它们旨在保持明确无歧义。 - Keith Thompson