簡體   English   中英

從數字字符串中獲取位

[英]Get bits from number string

如果我有一個數字字符串(字符數組),一個數字就是一個字符,導致四位數字的空間是 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 個字節來包含我的二進制形式的數字。 所以,如果我按照建議從后面開始一個一個地解析數字,那將如何建立最終的大二進制數?

通常,將字符串表示形式的數字轉換為十進制很容易,因為每個字符都可以單獨解析。 例如,要將"1024"轉換為1024您只需查看'4' ,將其轉換為4 ,乘以10 ,然后轉換2並添加它,乘以10 ,依此類推,直到您解析了整個字符串。

對於二進制它不是那么容易,例如您可以將4轉換為100201042不是100 010110或類似的東西。 因此,最好的辦法是將整個事物轉換為數字,然后使用數學運算(位移等)將該數字轉換為二進制。 這對於適合其中一種 C++ 數字類型的數字可以正常工作,但是如果您想處理任意大的數字,您將需要一個BigInteger類,這對您來說似乎是一個問題,因為代碼必須很小。

從您的問題中,我認為您想壓縮字符串表示以便通過網絡傳輸數字,因此我提供的解決方案不會嚴格轉換為二進制,但仍會使用比字符串表示更少的字節並且易於用。 它基於這樣一個事實:您可以將數字0..9存儲在 4 位中,因此您可以在一個字節中容納其中兩個數字。 因此,您可以在n/2字節中存儲n位數字。 該算法可能如下:

  • 取最后一個字符'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]

IE

digits = { 64, 33 }

這不是 1024 的二進制表示,但它更短,它允許您通過反轉算法輕松恢復原始數字。

您甚至還有 5 個不用於存儲數字的值(所有大於1010 ),您可以將它們用於其他內容,例如存儲符號、小數點、字節順序或數字結束分隔符)。

如果您選擇使用它,我相信您將能夠實現它。

如果我正確理解你的問題,你會想要這樣做:

  1. 將您的string表示形式轉換為integer
  2. integer轉換為binary表示。

對於第 1 步:

  • 你可以遍歷字符串
  • char減去'0'
  • 乘以10^n (取決於位置)並添加到總和。

對於第 2 步(對於int x ),通常:

  • x%2為您提供最低有效位 (LSB)。
  • x /= 2 “刪除” LSB。

例如,取x = 6

  • x%2 = 0 (LSB), x /= 2 -> x becomes 3
  • x%2 = 1 , x /= 2 -> x becomes 1
  • x%2 = 1 (MSB), x /= 2 -> 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)

將最多 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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM