Должен ли я использовать cstdint?

Я размышлял над тем, следует ли использовать typedef внутри <cstdint> или нет.

Я лично предпочитаю писать uint32_t над unsigned int и int8_t над char и т.д., так как это для меня гораздо более интуитивно.

Что вы, ребята, думаете? Это хорошая идея использовать typedefs из <cstdint> или нет? Есть ли недостатки?

Ответ 1

На самом деле, я бы предложил использовать оба.

Если вы хотите что-то определенно 32-битное без знака, используйте uint32_t. Например, если вы реализуете "struct" для представления внешнего объекта, спецификация которого определяет одно из его полей как 32 бита без знака.

Если вы хотите что-то, что является "натуральным размером слова машины", используйте int или unsigned int. Например:

for (int i = 0 ; i < 200 ; ++i)
    // stuff

"Естественный размер слова машины" даст вам лучшую производительность, как на сегодняшних процессорах, так и на завтрашнем дне.

Используйте "char", если вы имеете в виду "символ"; "char" или "unsigned char", если вы имеете в виду "байт". C/С++ позволяет вам обращаться к произвольным байтам объекта через "char *", а не что-либо еще, строго говоря.

Используйте uint8_t или int8_t, если вам требуется 8-разрядное целое число, подобное uint32_t.

Ответ 2

Вы должны использовать оба. Вы должны использовать int, как объяснено в других ответах, когда вам нужно "разумное размерное" целое число. Используйте char, когда вам нужен персонаж: он самодокументируется.

Вы должны использовать uint32_t и друзей при взаимодействии с внешним миром в двоичном формате: при программировании в сети, обработке двоичных файлов или использовании внешних многобайтовых кодировок и т.д. В этих случаях точный размер типа имеет решающее значение для написания правильного, портативного, самодокументирующего кода. Это то, что <stdint.h> (или С++ 0x <cstdint>) для.

(Конечность не менее важна, но это другое дело.)

Ответ 3

Это зависит от цели переменной.

Если вам нужен счетчик циклов, используйте int. Если вам нужна строка, используйте массив char.

Если вам нужна числовая переменная, которая может содержать от -1 до 100, int8_t - это хорошо. Если вам нужно представить значение от 0 до 100 000, то uint32_t uint_least32_t (спасибо @Serge) - отличный выбор.

Ответ 4

Одной конкретной ситуацией, в которой вам нужно будет использовать typedefs из cstdint, является обработка кода, который выполняет много преобразований с указателем на int, и в этом случае использование intptr_t является абсолютным требованием.

В компании, в которой я работаю, мы готовимся к переходу от 32 бит к 64-битным тоннам некачественного кода на C/С++, которые сохраняют указатели на ввод в int, а затем обратно к указателям, которые, безусловно, будут терпеть неудачу на 64-битных архитектурах, поэтому мы попытаемся всячески очищать код (т.е. модифицировать структуры данных и интерфейсы, чтобы полностью исключить необходимость приведения) и использовать intptr_t вместо int везде.

На стороне примечания: кастинг вообще должен поднять подозрение, но серьезно, указатели на целые числа почти всегда являются следствием серьезного недостатка в вашем дизайне. В принципе, вы лжете компилятору, платформе и, что более важно, вашим коллегам каждый раз, когда вы скрываете указатель за int.

Кроме этого, как и другие, говорят: используйте общие типы, когда это возможно, и тип явного размера, когда это требуется.

Ответ 5

У вас, похоже, нет никакой подсказки между uint32_t и unsigned int. Это совершенно нормально, поскольку вы не всегда знаете, как ваш тип будет использоваться позже.

Просто используйте typedef.

Независимо от того, нужен ли вам неподписанный int или uint32_t (о чем вы можете думать позже, когда у вас есть более полное представление о вашей программе), использование typedef поможет вам сделать код более понятным, указав, что вы действительно манипулируете, и это облегчит переход к другому типу, когда вы выберете месяцы после того, как ваш первоначальный выбор был самым худшим. Здесь нет "правильного ответа", потому что вы обычно делаете это с трудом. Взаимодействие между некоторой библиотекой, которая хочет uint32_t и некоторая другая библиотека, которая хочет ints, болезненна.

Ответ 6

Используйте template и общее программирование там, где это возможно. Не полагайтесь на любые типы, если вам это не нужно!

Если у вас есть функция, которая принимает число и возвращает его, умноженное на 2, напишите его следующим образом:

template <typename Number>
inline Number doubleNum(Number n) {
  return 2*n;
}

Или даже это:

template <typename RetType, typename NumberType>
inline RetType doubleNum(NumberType n) {
  return 2*n;
}

Таким образом, если у вас есть библиотека, использующая int s, double s, uint64_t - вы ее называете - вы можете работать с ней, не переписывая свой код. Если вам нужно работать с бинарными файлами или сетевым программированием, вы можете работать с типами фиксированного размера, не переписывая свой код. И если вам нужны произвольные числа точности, вы можете работать с классом, который реализует тот же интерфейс, что и примитивное целое число или тип float, через перегрузку оператора, например, оболочку GMP, без перезаписи кода.

И вы можете специализировать шаблонные функции или классы, оптимизировать конкретные случаи или работать с классами (или C struct s), которые не соответствуют соответствующему интерфейсу:

/*
 * optimization:
 * primitive integers can be bit-shifted left to
 * achieve multiplication by powers of 2
 * (note that any decent compiler will do this
 *  for you, behind the hood.)
 */
template <>
inline int doubleNum<int>(int n) {
  return n<<1;
}
/*
 * optimization:
 * use assembly code
 */
template <>
inline int32_t doubleNum<int32_t>(int32_t n) {
  asm {
    ...
  }
}
/*
 * work with awkward number class
 */
template <>
inline AwkwardNumber doubleNum<AwkwardNumber>(AwkwardNumber n) {
  n.multiplyBy(2);
  return n;
}