Объединение нескольких целых чисел в unsigned long long (64 бит) с побитовыми операторами

Я хотел бы закодировать данные о телефонном звонке на набор из 64 бит.

Есть 64 total: int caller(first 17 bits), int caller_zone(next 7 bits), int callee(17 bits), int callee_zone(7 bits), int duration(13 bits), int tariff(3 bits)

После расшифровки я хотел бы расшифровать его обратно. Я создал encode(...) метод, который кодирует данные, но я думаю, что это неправильно (потому что после расшифровки звонящего обратно номер другой).

Вопрос: Как исправить метод кодирования и как декодировать данные обратно?

Код компилируется и запускается (это легко понять, если запустить):

#include "stdafx.h"#include <iostream>

using namespace std;

unsigned long long encode(int caller, int caller_zone, int callee, int callee_zone, int duration, int tariff){
//I will shift every number to the left an ammount of times so they will cover seperate area of 64 bits of unsigned long long
unsigned long long p1 = caller;
int shift = 64 - 17;//first 17 bits
p1 = __ll_lshift(p1, shift);
unsigned long long p2 = caller_zone;
p2 = __ll_lshift(p2, (shift -= 7));//next 7 bits
unsigned long long p3 = callee;
p3 = __ll_lshift(p3, (shift -= 17));//next 17 bits
unsigned long long p4 = callee_zone;
p4 = __ll_lshift(p4, (shift -= 7));//next 7 bits
unsigned long long p5 = duration;
p5 = __ll_lshift(p5, (shift -= 13));//next 13 bits
unsigned long long p6 = tariff;//last 3 bits
return p1 | p2 | p3 | p4 | p5 | p6;
}
void info(long long val){
unsigned long long val1 = 0;
//
int caller; int caller_zone;
int callee; int callee_zone;
int duration; int tariff;

caller = __ll_lshift(ULLONG_MAX & val, 64 - 17);

cout << "caller:      " << caller << endl;
}
int main(){
int caller = 130999; int caller_zone = 101;
int callee = 7777; int callee_zone = 99;
int duration = 7000; int tariff = 6;
cout << "FROM MAIN" << endl;
cout << "caller:      " << caller << endl
<< "caller zone: " << caller_zone << endl
<< "calee:       " << callee << endl
<< "calee zone:  " << callee_zone << endl
<< "duration:    " << duration << endl
<< "tariff:      " << tariff << endl;

unsigned long long u = encode(caller, caller_zone, callee, callee_zone, duration, tariff);
cout << u << endl;// do skasowania
cout << "\n FROM INFO" << endl;
info(u);
cout << "cos" << endl;
int val = 21;
val = __ll_lshift(val, 1);
cout << val << endl;
system("pause");
return 0;
}

1

Решение

Похоже, что вы делаете кодировку так, как вы намеревались, хотя вам придется посмотреть на выходные данные следующей программы, чтобы определить наверняка.

Я украл функцию из этот ответ, и немного изменил ваш код, чтобы быть более переносимым.

#include <iostream>
#include <stdint.h>
#include <limits.h>
#include <stdio.h>using namespace std;//assumes little endian
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;

for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = b[i] & (1<<j);
byte >>= j;
printf("%u", byte);
}
}
puts("");
}

uint64_t encode(int caller, int caller_zone, int callee, int callee_zone, int duration, int tariff){
uint64_t p1 = caller;
int shift = 64 - 17;//first 17 bits
p1 = p1 << shift;
uint64_t p2 = caller_zone;
p2 = p2 << (shift -= 7); //next 7 bits
uint64_t p3 = callee;
p3 = p3 << (shift -= 17); //next 17 bits
uint64_t p4 = callee_zone;
p4 = p4 << (shift -= 7); //next 7 bits
uint64_t p5 = duration;
p5 = p5 << (shift -= 13);//next 13 bits
uint64_t p6 = tariff;//last 3 bits

printBits(8, &p1);
printBits(8, &p2);
printBits(8, &p3);
printBits(8, &p4);
printBits(8, &p5);
printBits(8, &p6);

uint64_t result = p1 | p2 | p3 | p4 | p5 | p6;
printBits(8, &result);
return result;
}

int main(){
int caller = 130999; int caller_zone = 101;
int callee = 7777; int callee_zone = 99;
int duration = 7000; int tariff = 6;

unsigned long long u = encode(caller, caller_zone, callee, callee_zone, duration, tariff);
return 0;
}

Выход:

1111111111011011100000000000000000000000000000000000000000000000
0000000000000000011001010000000000000000000000000000000000000000
0000000000000000000000000000111100110000100000000000000000000000
0000000000000000000000000000000000000000011000110000000000000000
0000000000000000000000000000000000000000000000001101101011000000
0000000000000000000000000000000000000000000000000000000000000110
1111111111011011111001010000111100110000111000111101101011000110
1

Другие решения

А вот функция декодирования:

#include <iostream>
#include <tuple>

using namespace std;

std::tuple<int, int, int, int, int, int> decode(uint64_t bits) {
int tariff = bits & 0x7;
bits >>= 3;

int duration = bits & 0x1fff;
bits >>= 13;

int callee_zone = bits & 0x7f;
bits >>= 7;

int callee = bits & 0x1ffff;
bits >>= 17;

int caller_zone = bits & 0x7f;
bits >>= 7;

int caller = bits & 0x1ffff;

return std::make_tuple(caller, caller_zone, callee, callee_zone, duration, tariff);
}

int main()
{
uint64_t encodedBits = 0b1111111111011011111001010000111100110000111000111101101011000110;

int caller = 0; int caller_zone = 0;
int callee = 0; int callee_zone = 0;
int duration = 0; int tariff = 0;

std::tie(caller, caller_zone, callee, callee_zone, duration, tariff) = decode(encodedBits);

cout << caller << endl
<< caller_zone << endl
<< callee << endl
<< callee_zone << endl
<< duration << endl
<< tariff << endl;

return 0;
}
1