読者です 読者をやめる 読者になる 読者になる

64ビット整数を8ビット配列に格納

(uint64_t)64ビット整数を(uint8_t)8ビット配列に格納する際、8成分必要です。番兵を入れれば9成分でしょうか。同じ最大9成分でも、それぞれの成分の1ビット分を次があるかどうかを示すフラグにする方法も考えられます。メリットとしては、成分が少ないときほどフラグに使用するビット数が減る程度のことのように思いますが、どうなんでしょう。

8ビット配列に入る値は次の3種あります。
A=0x[7] :0は次はないことを示します。残り7ビットは値が入ります。
B=1x[7] :1は次の成分があることを示します。残り7ビットは値が入ります。
C=x[8] : 7か8成分の値と符号フラグが入ります。
7ビットから64ビットまでの場合があって、次のようになります。
7: A
14: BA
21: BBA
28: BBBA
35: BBBBA
42: BBBBBA
49: BBBBBBA
56: BBBBBBBA
64: BBBBBBBBC

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
void putVarint(uint8_t* buf, uint64_t k) {
    buf[8] = (uint8_t)k;
  if(k & (0xff000000llu << 32))   
    k >>= 8;
  else
    k >>= 7;
  int i = 7;
  while(k != 0) {
    buf[i--] = (uint8_t)((k & 0x7f)| 0x80);
    k >>= 7;
  }
}
int getVarint(uint8_t* p, uint64_t *v) {
int i = 0;
  while(!*p) {
    p++;
    i++;
  }
int is_full = 0 == i;
  *v = 0;
int j;
  for(j = i; (j < 8) && (*p&0x80) != 0; j++) {
    *v |= (*p++&0x7f);
    *v <<= 7;
  }
  assert(j == 8);
  if(is_full)
    *v <<= 1;
  *v |= *p;
  return j-i+1;
}
int main(void) {
//64bits case
  {
  uint8_t buf[9];
  uint64_t k = 0x1234567890ABCDEFllu;
  int64_t value;
  memset(buf, 0, 9 * sizeof(buf[0]));
  putVarint(buf, k);
  assert(9 == getVarint(buf,&value));
  assert(0x1234567890ABCDEFllu == value);
  }
// small number case
  {
  uint8_t buf[9];
  uint64_t k = 0x123llu;
  int64_t value;
  memset(buf, 0, 9 * sizeof(buf[0]));
  putVarint(buf, k);
  assert(0x123llu == (long long int)((int64_t)(buf[7]&0x7f) << 7| (int64_t)buf[8])); 
  assert(2 == getVarint(buf,&value));
  assert(0x123llu == value);
  }
// signed case
  {
  uint8_t buf[9];
  int64_t i = -0x12345llu;
  uint64_t k = i;
  int64_t value;
  memset(buf, 0, 9 * sizeof(buf[0]));
  assert(i && 0xff000000llu << 32);
  putVarint(buf, k);
  assert(9 == getVarint(buf,&value));
  assert(-0x12345llu == value);
  }
  return 0;
}