从数字字符串中获取位

时间:2016-04-20 07:55:36

标签: c

如果我有一个数字字符串(字符数组),一个数字是一个字符,导致四位数的空格是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个字节来包含二进制形式的数字。所以,如果我建议逐个解析数字,从后面开始,那将如何构建最终的大二进制数?

3 个答案:

答案 0 :(得分:1)

通常,将字符串表示中的数字转换为十进制很容易,因为每个字符都可以单独解析。例如。要将"1024"转换为1024,您只需查看'4',将其转换为4,乘以10,然后转换为2并添加它,乘以10,依此类推,直到你解析了整个字符串。

对于二进制文件来说,这并不容易,例如您可以将4转换为100,将2转换为010,但42不是100 010110或类似的内容。因此,您最好的选择是将整个事物转换为数字,然后使用数学运算(位移等)将该数字转换为二进制数。这适用于适合其中一种C ++数字类型的数字,但是如果你想处理任意大数字,你需要一个BigInteger类,这对你来说似乎是一个问题,因为代码必须很小

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

  • 取最后一个字符'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的所有内容),您可以将其用于存储符号,小数点等其他内容,字节顺序或数字结束分隔符。)

我相信如果你选择使用它,你将能够实现它。

答案 1 :(得分:0)

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

  1. 将您的string表示转换为integer
  2. integer转换为binary表示。
  3. 对于第1步:

    • 你可以遍历字符串
    • '0'
    • 中减去char
    • 乘以10^n(取决于位置)并加总。

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

    • x%2为您提供最低有效位(LSB)。
    • x /= 2&#34;删除&#34; LSB。

    例如,取x = 6

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

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

    关于实施(针对N=2,其中N的最大数量为bytes):

    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)
    

答案 2 :(得分:0)

要将表示为字符串的最多30位十进制数转换为严重的字节,实际上基数为256的表示形式最多需要13个字节。 (天花板30 / log10(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;
}