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