Как получить наименьшее количество байтов, необходимых для хранения целочисленного значения с помощью макроса? - PullRequest
1 голос
/ 15 октября 2011

Например, если целое число меньше 255, то его можно восстановить в 1 байт,

, если оно больше 255, требуется как минимум 2 байт.

Как написать такой BYTES_REQUIRED(i) макрос?

Ответы [ 4 ]

0 голосов
/ 15 октября 2011

К сожалению, вы просили макрос C, потому что эта шаблонная функция C ++ могла бы быть полезной (она должна работать для любого целочисленного типа, поддерживаемого вашим компилятором).

template <typename T> int bytesRequired(T value) {
  boost::function_requires< boost::IntegerConcept<T> >();
  for (int i=0; i<=sizeof(T); i++, value/=256)
    if (value == 0) return i;
}

Другой подход, который должен быть быстрее (потому что он не имеет ответвлений), если вам нужна не просто оценка во время компиляции, это битовый скан, который упоминал Алекс.

0 голосов
/ 15 октября 2011

Используется эффективный подход «разделяй и властвуй»:

#define BYTES_REQUIRED(i) (((i) & 0xFFFF0000) ? (((i) & 0xFF000000) ? 4 : 3) : (((i) & 0xFF00) ? 2 : 1))

Если вы не возражаете, исключив нечетный регистр из 3 байтов, у которого нет примитивного типа, который соответствует ему, выполните:

#define BYTES_REQUIRED(i) (((i) & 0xFFFF0000) ? 4 : (((i) & 0xFF00) ? 2 : 1))

Имейте в виду, что ни один из этих символов не обрабатывает отрицательные числа, поскольку он видит знак, расширенный на 1 бит, как использованное пространство.Это требует другого условия для учета (например, если отрицательное, отрицание).

0 голосов
/ 15 октября 2011

Вам нужно эффективно рассчитать log2 (i). Не существует тривиального способа сделать это мобильно, быстро, для максимального целочисленного значения, поддерживаемого компилятором и с помощью макроса.

Опции:

1.Рассчитайте логарифм в цикле:

// 64+-bit version:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long bits = 0;
  while (i)
  {
    i >>= 1;
    bits++;
  }
  if (bits == 0) bits = 1;
  return (bits + 7) / 8; // we're assuming that byte=8 bits, but CHAR_BIT may be > 8
}

2.Используйте встроенную функцию (фактически выделенную инструкцию ЦП) компилятора, если она доступна. Для MSVC ++:

// 64-bit version, not available for 32-bit code:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long index;
  if (_BitScanReverse64(&index, i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

// 32-bit version, available for 32 and 64-bit code:
unsigned long BYTES_REQUIRED(unsigned long i)
{
  unsigned long index;
  if (_BitScanReverse(&index, i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

// 64-bit version available for 32 and 64-bit code:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long index;
  if (_BitScanReverse(&index, (unsigned long)(i >> 32)))
  {
    index += 32;
  }
  else if (_BitScanReverse(&index, (unsigned long)i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

3.Используйте if или ?:, зная размер самого большого поддерживаемого целочисленного типа ... Другие уже описали этот метод.

0 голосов
/ 15 октября 2011

Если вы используете компилятор C99, приведите приведенное ниже значение к (unsigned long long).Также вы можете (и должны) расширить конструкцию до 8 или 16 байтов (это оставлено как упражнение)

#include <limits.h>

#define BYTES_REQUIRED(i)                            \
           !((unsigned long)(i) >>     CHAR_BIT) ? 1 \
         : !((unsigned long)(i) >> 2 * CHAR_BIT) ? 2 \
         : !((unsigned long)(i) >> 3 * CHAR_BIT) ? 3 \
         :                                         4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...