如何在C++中将整数转换为二进制字符串表示

17

我有一个整数,想将其存储为二进制字符串表示。如何实现?


1
整数(以及所有其他数据)已经以二进制形式存储。没有“转换”。 - WhirlWind
你想将它存储在字符串中的二进制形式(例如0x1e3f:4字节,适用于在文件中存储数据)还是二进制字符表示(例如10110111...:32字节,完全没有用处)? - Stephen
我想要一个二进制的字符表示。比如10101011101。 - neuromancer
@Shaggy:如果这是一份作业,那么它似乎只是一个更大项目的一小部分:http://stackoverflow.com/questions/2890480/array-size-for-extendible-hashing。使用可扩展哈希,您可以将哈希视为位字符串,也许不是字面上的,但可能是为了记录/调试目的。 - Brian R. Bondy
这篇文章可能有所帮助 https://dev59.com/dHVD5IYBdhLWcg3wBm5h - zebrabox
10个回答

44

试试这个:

#include <bitset>
#include <iostream>
int main()
{
    std::bitset<32>      x(23456);
    std::cout << x << "\n";


    // If you don't want a variable just create a temporary.
    std::cout << std::bitset<32>(23456) << "\n";
}

这是保证可行的,接受的答案在我的情况下存在前导零问题。 - Bar

15
我有一个整数,我想先将其转换为二进制数。
这到底是什么意思呢?不存在“二进制数”类型。好吧,除非你使用非常奇怪的计算机,否则一个 int 已经在内部以二进制形式表示了,但这只是一种实现细节——从概念上讲,它只是一个整数。
每次将数字打印到屏幕上时,它必须被转换为一个字符字符串。恰好大多数 I/O 系统选择了十进制表示来进行这个过程,以便人类更容易理解。但 int 并没有固有的十进制属性。
无论如何,要生成一个整数 x 的基数为 b 的表示,只需按照以下算法操作:
  1. 用空字符串初始化 s
  2. m = x % b
  3. x = x / b
  4. m 转换为数字,即 d
  5. s 上附加 d
  6. 如果 x 不为零,则转到步骤 2。
  7. 反转 s
如果 b <= 10 并且计算机使用一种字符编码,其中数字 0-9 是连续的,则步骤 4 很容易,因为它只是 d = '0' + m。否则,您需要一个查找表。
如果您提前知道需要多少空间并从字符串的右端开始,则可以将步骤 5 和 7 简化为在 s 的左侧附加 d
b == 2 的情况下(例如二进制表示),步骤 2 可以简化为 m = x & 1,步骤 3 可以简化为 x = x >> 1
使用 reverse 的解决方案:
#include <string>
#include <algorithm>

std::string binary(unsigned x)
{
    std::string s;
    do
    {
        s.push_back('0' + (x & 1));
    } while (x >>= 1);
    std::reverse(s.begin(), s.end());
    return s;
}

没有使用 reverse 的解决方案:

#include <string>

std::string binary(unsigned x)
{
    // Warning: this breaks for numbers with more than 64 bits
    char buffer[64];
    char* p = buffer + 64;
    do
    {
        *--p = '0' + (x & 1);
    } while (x >>= 1);
    return std::string(p, buffer + 64);
}

@FredOverflow,您能否进一步解释一下 x>>=1 是什么意思/作用? - AK_
@AK_ 它的意思是“将x中的所有位向右移动一位”。对于无符号整数来说,它和x /= 2有完全相同的语义。 - fredoverflow
@fredOverflow,仍然不太清楚 - 我知道x>>1表示向右移动一位,但是在这里你写的while(x>>=1)是什么意思?它是否表示向右移动1位并检查是否为1,然后继续循环?如果x=10000011b怎么办?那么在第3次向右移动时,循环不会中断吗?- 再次感谢! - AK_
1
@AK_ 不,当 x 的值为0时,“条件”变为假;也就是说,当所有比特位都为0时。 - fredoverflow

2

将数字与100000...、010000...、0010000...等进行 AND 操作。每次操作,如果结果为0,则在字符数组中放置一个“0”,否则放置一个“1”。

int numberOfBits = sizeof(int) * 8;
char binary[numberOfBits + 1];
int decimal = 29;

for(int i = 0; i < numberOfBits; ++i) {
    if ((decimal & (0x80000000 >> i)) == 0) {
        binary[i] = '0';
    } else {
        binary[i] = '1';
    }
}
binary[numberOfBits] = '\0';
string binaryString(binary);

2

http://www.phanderson.com/printer/bin_disp.html 是一个很好的例子。

一个简单方法的基本原理:

  • 循环直到 # 等于 0
  • 对 # 进行位与(&)1,将结果(1 或 0)打印到字符串缓冲区的末尾。
  • 使用 >>= 将 # 向右移动 1 位。
  • 重复循环
  • 打印反转后的字符串缓冲区

为了避免反转字符串或需要限制自己只能使用适合缓冲字符串长度的 #,您可以:

  • 计算 ceiling(log2(N)) - 假设为 L
  • 计算 mask = 2^L
  • 循环直到 mask == 0:
  • 对 mask 和 # 进行位与(&),将结果(1 或 0)打印出来。
  • number &= (mask-1)
  • mask >>= 1(除以 2)

我不想仅仅打印一个二进制数,我想将它存储在一个字符串中。 - neuromancer
1
不,答案并不完美,但为什么不考虑一下,然后你就会永远知道了呢? - WhirlWind
1
你不需要“打印”它。想象一下他说:“将结果放在字符串缓冲区的末尾”。 - Stephen

1

我假设这与您在可扩展哈希问题上的其他问题有关。

首先为您的位定义一些助记符:

const int FIRST_BIT = 0x1;
const int SECOND_BIT = 0x2;
const int THIRD_BIT = 0x4;

然后你有一个要转换为比特串的数字:

int x = someValue;

您可以使用逻辑运算符&来检查位是否已设置。
if(x & FIRST_BIT)
{
    // The first bit is set.
}

你可以保留一个std::string,如果某个位被设置了,就在该字符串中添加1,如果该位未设置,则添加0。根据您想要的字符串顺序,您可以从最后一位开始移动到第一位,或者只是从第一位到最后一位。

您可以将此重构为循环,并通过在每次迭代后使用current_bit_value<<=1来计算上面的助记符位,从而将其用于任意大小的数字。


+1 对于研究用户的其他帖子(以及答案本身)来说是非常有价值的。 - Adam

0
没有反转、不增加额外的副本,并且带有0填充的解决方案:
#include <iostream>
#include <string>

template <short WIDTH>
std::string binary( unsigned x )
{
    std::string buffer( WIDTH, '0' );
    char *p = &buffer[ WIDTH ];

    do {
        --p;
        if (x & 1) *p = '1';
    }
    while (x >>= 1);

    return buffer;
}

int main()
{
    std::cout << "'" << binary<32>(0xf0f0f0f0) << "'" << std::endl;
    return 0;
}

0

这里有一个小的仅包含头文件的库,你可以用它来实现这个功能 here

例子:

std::cout << ConvertInteger<Uint32>::ToBinaryString(21);
// Displays  "10101"

auto x = ConvertInteger<Int8>::ToBinaryString(21, true);
std::cout << x << "\n"; // displays "00010101"

auto x = ConvertInteger<Uint8>::ToBinaryString(21, true, "0b");
std::cout << x << "\n"; // displays "0b00010101"

0

没有直接的函数,您可以沿着 int 的位(提示参见 >>)行进,并在字符串中插入“1”或“0”。
听起来像是标准的面试/作业类型问题


0
使用 sprintf 函数将格式化输出存储在字符串变量中,而不是直接使用 printf 进行打印。请注意,这些函数仅适用于 C 字符串,而不是 C++ 字符串。

0
这是我最好的将整数(任何类型)转换为std :: string的实现。如果您只打算使用单个整数类型,则可以删除模板。据我所知,我认为C ++的安全性和C的神秘本质之间存在良好的平衡。确保包含所需的标头。
template<typename T>
std::string bstring(T n){
    std::string s;
    for(int m = sizeof(n) * 8;m--;){
            s.push_back('0'+((n >> m) & 1));
    }
    return s;
}

像这样使用它,

std::cout << bstring<size_t>(371) << '\n';

这是我的电脑上的输出(每台电脑都不同),
0000000000000000000000000000000000000000000000000000000101110011

请注意,整个二进制字符串都会被复制,因此填充的零有助于表示位大小。因此,字符串的长度是size_t以位为单位的大小。
让我们尝试一个带符号整数(负数)。
std::cout << bstring<signed int>(-1) << '\n';

这是我的电脑上的输出(如所述,每台计算机都有所不同),

11111111111111111111111111111111

请注意,现在字符串更小了,这证明了 signed intsize_t 占用更少的空间。正如您所看到的,我的计算机使用 2's complement method 来表示 signed integers(负数)。现在您可以看到为什么 unsigned short(-1) > signed int(1)
这是一个专门针对 signed integers 的版本,以使此函数无需模板,即如果您只打算将 signed integers 转换为字符串,请使用此版本。
std::string bstring(int n){
    std::string s;
    for(int m = sizeof(n) * 8;m--;){
            s.push_back('0'+((n >> m) & 1));
    }
    return s;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接