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

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

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

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

6 ответов

Решение

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

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

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

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

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

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

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

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

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

(Endianness одинаково важен, но это совсем другое дело.)

Это зависит от назначения переменной.

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

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

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

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

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

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

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

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

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

Использование 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;
}

Таким образом, если у вас есть библиотека, которая использует ints, doubles, uint64_ts - вы называете это - вы можете работать с ним, не переписывая свой код. Если вам нужно работать с двоичными файлами или сетевым программированием, вы можете работать с типами фиксированного размера, не переписывая код. А если вам нужны числа произвольной точности, вы можете работать с классом, который реализует тот же интерфейс, что и примитивный целочисленный тип или тип с плавающей запятой, посредством перегрузки операторов, такой как обертка GMP, без переписывания кода.

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

/*
 * 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;
}
Другие вопросы по тегам