Должен ли я использовать 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_t
uint_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;
}
Таким образом, если у вас есть библиотека, которая использует int
s, double
s, uint64_t
s - вы называете это - вы можете работать с ним, не переписывая свой код. Если вам нужно работать с двоичными файлами или сетевым программированием, вы можете работать с типами фиксированного размера, не переписывая код. А если вам нужны числа произвольной точности, вы можете работать с классом, который реализует тот же интерфейс, что и примитивный целочисленный тип или тип с плавающей запятой, посредством перегрузки операторов, такой как обертка 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;
}