Можно ли создать тип переменной в си с любым размером
Можно ли создать тип переменной в си с любым размером, и чтоб можно было работать с битовыми операциями!. Вот я хочу создать аналог int который будет 128 битовый, или 256 битовый итд И чтоб я мог складывать и вычитать и делить итд
Ответы (1 шт):
Принципиально в C это сделать можно, но выглядеть будет не так удобно, как, например, в объектно-ориентированном языке с перегрузкой операторов, таком, как C++.
Сначала, о том, как это делается в принципе. Огромные числа можно представить как последовательности (массивы) байтов.
Для простоты представим, что числа у нас беззнаковые и хранятся в массиве из 20-ти байт.
unsigned char a[20] = { 0x00, 0x00, …, 0xC0, 0xD0 };
unsigned char b[20] = { 0x00, 0x01, …, 0xF0, 0xFF };
unsigned char c[20];
В каждом байте может храниться 256 разных значений, поэтому наш массив представляет как бы 20-тизначное число в системе счисления 256.
Оно равно 25619*c[0]+25618*c[1]+...+2561*c[18]+2560*c[19]
Такой порядок соответствует тому, как мы записываем числа на бумаге: сначала старшие разряды, а в конце младшие, сначала миллионы, в конце единицы.
Чтобы сложить два больших числа мы действуем также, как и при сложении в столбик, начиная с младших разрядов.
Если бы мы складывали 17 и 25, то сначала бы сложили 7 и 5 и получили бы 12. Мы записали в младший разряд результата 2 (остаток от деления 12 на 10, потому что у нас десятичная система). Поскольку 12 больше 10, нам придётся прибавить 1 к сумме 1 и 2, то есть «перенести единицу».
Сложение чисел с 256-тизначной системе выглядит точно также. Начинать надо с младшего 19-го байта и подниматься к старшему 0-му байту:
unsigned char curry = 0;
for (int i = 19; i >= 0; i--) {
int sum = a[i] + b[i] + curry;
c[i] = sum % 256;
curry = sum > 256 ? 1 : 0;
}
Здесь curry это значение переноса. Оно равно 0, если переноса нет, то есть сумма на предыдущем шаге меньше 256. Оно равно 1, если перенос есть. В c[i] мы сохраняем остаток от деления суммы двух цифр на 256.
Всё точно также, как и со сложением десятичных чисел, только вместо 10 у нас 256.
Естественно, алгоритм можно обобщить на массивы любой длины. В этом случае вам придётся хранить не только его байты-цифры, но и длину массива.
Для алгоритма умножения можно адаптировать умножение в столбик, либо использовать более быстрый алгоритм, такой как алгоритм Карацубы.
В C работу с большими числами нельзя сделать простой, потому что вам придётся написать функции сложения, которые вы будете вызывать приблизительно так:
BIGINT* a = bigint_from_int(100);
BIGINT* b = bigint from_str("9035801984122098342750239485334875");
BIGINT* c = bigint_add(a, b);
В C++ вы можете спрятать детали реализации внутрь класса и определить для него операторы сложения, умножения и так далее:
bigint a(100);
bigint b("9035801984122098342750239485334875");
bigint c = a + b;
В сети есть множество библиотек с открытым кодом, где это уже сделано, например kasparsklavins/bigint на GitHub.