2016-04-20 205 views
-2

如果我有一个数字字符串(字符数组),一个数字是一个字符,导致四位数字的空间是5个字节,包括空终止。从数字字符串获取位

unsigned char num[] ="1024"; 
printf("%d", sizeof(num)); // 5 

然而,1024可以写成

unsigned char binaryNum[2]; 
binaryNum[0] = 0b00000100; 
binaryNum[1] = 0b00000000; 

如何从字符串到二进制转换来有效地使? 在我的程序中,我会使用≈30位数字,所以空间增益会很大。 我的目标是创建通过UDP/TCP发送的数据包。

我不希望使用库来执行此任务,因为代码可用的空间很小。编辑: 感谢您的快速回复。

char num = 0b0000 0100 // "4" 
-------------------------- 
char num = 0b0001 1000 // "24" 
----------------------------- 
char num[2]; 
num[0] = 0b00000100; 
num[1] = 0b00000000; 
// num now contains 1024 

我需要≈10个字节来包含我的二进制形式的数字。因此,如果我建议从后面开始逐个解析数字,那么如何构建最终的大二进制数?

+0

首先,'sizeof'返回一个'size_t'数量,即'长unsigned'。最好在printf中使用'“%lu”'。 – Boiethios

+0

不知道我是否完全理解了这个问题,但是您是否考虑过对数字进行数字解析?你可以从char中减去'0',你会得到一个数字 –

+0

为什么你不使用'atoi'? – Boiethios

回答

1

通常,将字符串表示中的数字转换为十进制很容易,因为每个字符都可以分别进行分析。例如。到"1024"转换为1024你可以看看'4',将其转换为4,由10大量繁殖,然后转换210添加它,乘法,依此类推,直到你已经解析了整个字符串。

对于二进制,它并不是那么容易,例如,您可以将4转换为1002010,但42不是100 010110或类似的东西。所以,你最好的选择是将整个事物转换为数字,然后使用数学运算(位移等)将该数字转换为二进制数。对于符合C++数字类型之一的数字,这将工作得很好,但如果要处理任意大的数字,则需要BigInteger类,这对您来说似乎是个问题,因为代码必须很小。

从你的问题我收集到,你想压缩字符串表示,以便通过网络传输数字,所以我提供的解决方案,不严格转换为二进制文件,但仍然会使用比字符串表示更少的字节并且易于使用。它基于这样一个事实,即您可以用4位存储数字0..9,因此您可以将这两个数字放在一个字节中。因此,您可以在n/2字节中存储一个n -digit数字。该算法可以如下:

  • 采取的最后一个字符,'4'
  • 减去'0'得到4(即一个具有价值4 INT)。
  • 去掉最后一个字符。
  • 重复以获得0
  • 连接成一个字节:digits[0] = (4 << 4) + 0
  • 对接下来的两个数字做同样的处理:digits[1] = (2 << 4) + 1

你在内存中表示,现在看起来像

4 0  2 1 
0100 0000 0010 0001  

digits[0] digits[1] 

digits = { 64, 33 } 

这不是1024相当的二进制表示的,但它是短,它可以让你轻松恢复原始数字通过颠倒算法。

你甚至有5个值留下,你不用于存储数字(一切比1010大),你可以用其他的东西像存储符号,小数点,字节顺序或使用的最终OF-号码分隔符)。

我相信你可以实现这一点,如果你选择使用它。

+0

感谢您的建议!非常好地呈现。我会试一试,看看它在我的情况下的表现如何。 – Ludste

0

如果我正确理解你的问题,你会想这样做:

  1. 将您string表示为integer
  2. integer转换为binary表示形式。

对于步骤1:

  • 你可以通过10^n(取决于位置)将字符串
  • 减去'0'char
  • 乘法循环,并加入到一个总和。

对于第2步(为int x),一般来说:

  • x%2给你最不显著位(LSB)。
  • x /= 2“移除”LSB。

例如,取x = 6

  • x%2 = 0(LSB),x /= 2 - >x becomes 3
  • x%2 = 1x /= 2 - >x becomes 1
  • x%2 = 1(MSB),x /= 2 - >x becomes 0

所以我们看到(6)decimal == (110)bin

上到实现(N=2,其中Nbytes最大数量):

int x = 1024; 
int n=-1, p=0, p_=0, i=0, ex=1; //you can use smaller types of int for this if you are strict on memory usage 
unsigned char num[N] = {0}; 

for (p=0; p<(N*8); p++,p_++) { 

    if (p%8 == 0) { n++; p_=0; } //for every 8bits, 1) store the new result in the next element in the array. 2) reset the placing (start at 2^0 again). 

    for (i=0; i<p_; i++) ex *= 2; //ex = pow(2,p_); without using math.h library 

    num[n] += ex * (x%2); //add (2^p_ x LSB) to num[n] 
    x /= 2; // "remove" the last bit to check for the next. 
    ex = 1; // reset the exponent 
} 

我们可以检查结果为x = 1024

for (i=0; i<N; i++) 
    printf("num[%d] = %d\n", i, num[i]); //num[0] = 0 (0b00000000), num[1] = 4 (0b00000100) 
+0

谢谢你的回答。这看起来像一个很有前途的解决方案,但如何处理更大的数字呢?说原始字符串是30位数字。那么int就不够用了。 – Ludste

+0

@Ludste将它切成15个2位数的字符串。将它们中的每一个转换为一个“字节”。发送全部15个字节。将每个“字节”转换为“2位数int”和随后的“2位数字符串”。连接所有'15'字符串。 我只提供了上面的答案,以显示如何以您想要的方式将'int'转换为二进制表示形式!但那不一定是大整数的最佳方式。 – Lincoln

0

要转换上30十进制数字表示为一个字符串,转换为严格的字节,实际上是一个256位的表示,最多占用13个字节。 (30 /日志10(256)的上限)

简单算法

dest = 0 
for each digit of the string (starting with most significant) 
    dest *= 10 
    dest += digit 

作为C代码

#define STR_DEC_TO_BIN_N 13 

unsigned char *str_dec_to_bin(unsigned char dest[STR_DEC_TO_BIN_N], const char *src) { 
    // dest[] = 0 
    memset(dest, 0, STR_DEC_TO_BIN_N); 

    // for each digit ... 
    while (isdigit((unsigned char) *src)) { 

    // dest[] = 10*dest[] + *src 
    // with dest[0] as the most significant digit 
    int sum = *src - '0'; 
    for (int i = STR_DEC_TO_BIN_N - 1; i >= 0; i--) { 
     sum += dest[i]*10; 
     dest[i] = sum % 256; 
     sum /= 256; 
    } 

    // If sum is non-zero, it means dest[] overflowed 
    if (sum) { 
     return NULL; 
    } 
    } 
    // If stopped on something other than the null character .... 
    if (*src) { 
    return NULL; 
    } 

    return dest; 
}