Когда я впервые выучил язык C ++, я узнал, что, кроме int, float и т. Д., В этом языке существуют меньшие или большие версии этих типов данных. Например, я мог бы назвать переменную х
int x;
or
short int x;
Основное отличие состоит в том, что short int занимает 2 байта памяти, тогда как int занимает 4 байта, а short int имеет меньшее значение, но мы могли бы также вызвать его, чтобы сделать его еще меньше:
int x;
short int x;
unsigned short int x;
что еще более ограничительно.
Мой вопрос здесь заключается в том, является ли хорошей практикой использование отдельных типов данных в зависимости от того, какие значения принимает ваша переменная в программе. Является ли хорошей идеей всегда объявлять переменные в соответствии с этими типами данных?
c++
data-structures
Bugster
источник
источник
unsigned
так или иначе заставляет целое число занимать меньше места, что, конечно, неверно. Он будет иметь такое же количество дискретных представимых значений (давать или брать 1 в зависимости от того, как представлен знак), но просто смещается исключительно в положительное значение.Ответы:
В большинстве случаев стоимость места незначительна, и вам не следует об этом беспокоиться, однако вам следует беспокоиться о дополнительной информации, которую вы предоставляете, объявляя тип. Например, если вы:
Вы даете полезную информацию другому разработчику: зарплата не может быть отрицательной.
Разница между short, int, long редко вызывает проблемы с пространством в вашем приложении. Вы, скорее всего, случайно сделаете ложное предположение, что число всегда будет соответствовать какому-либо типу данных. Вероятно, безопаснее всегда использовать int, если вы не уверены на 100%, что ваши цифры всегда будут очень маленькими. Даже тогда, это вряд ли сэкономит вам сколько-нибудь заметное количество места.
источник
unsigned
в этом случае плохая идея: не только зарплата не может быть отрицательной, но и разница между двумя зарплатами также не может быть отрицательной. (В общем, использование unsigned для чего-либо, кроме разбивки битов, и определение поведения при переполнении - плохая идея.)ОП ничего не сказал о типе системы, для которой они пишут программы, но я предполагаю, что ОП думала о типичном ПК с ГБ памяти, поскольку упоминается C ++. Как говорится в одном из комментариев, даже с таким типом памяти, если у вас есть несколько миллионов элементов одного типа - например, массива - тогда размер переменной может иметь значение.
Если вы попадаете в мир встраиваемых систем - который на самом деле не выходит за рамки вопроса, поскольку OP не ограничивает его ПК - тогда размер типов данных очень важен. Я только что закончил быстрый проект на 8-битном микроконтроллере, который имеет только 8 тыс. Слов памяти программ и 368 байт оперативной памяти. Там, очевидно, каждый байт имеет значение. Никто никогда не использует переменную больше, чем им нужно (как с точки зрения пространства, так и размера кода - 8-битные процессоры используют много инструкций для манипулирования 16- и 32-битными данными). Зачем использовать процессор с такими ограниченными ресурсами? В больших количествах они могут стоить всего четверть.
В настоящее время я работаю над другим встраиваемым проектом с 32-разрядным микроконтроллером на основе MIPS, который имеет 512 Кбайт флэш-памяти и 128 Кбайт оперативной памяти (и стоит около $ 6). Как и в случае с ПК, «естественный» размер данных составляет 32 бита. Теперь с точки зрения кода становится более эффективным использование целочисленных значений для большинства переменных вместо символов или кратких значений. Но еще раз, любой тип массива или структуры должен быть рассмотрен, гарантированы ли меньшие типы данных. В отличие от компиляторов для более крупных систем, более вероятно, что переменные в структуре будут упакованы во встроенную систему. Я стараюсь всегда ставить сначала все 32-битные переменные, затем 16-битные, а затем 8-битные, чтобы избежать каких-либо «дырок».
источник
Ответ зависит от вашей системы. В общем, вот преимущества и недостатки использования меньших типов:
преимущества
Недостатки
Я советую вот так:
В качестве альтернативы вы можете использовать
int_leastn_t
илиint_fastn_t
из stdint.h, где n - это число 8, 16, 32 или 64.int_leastn_t
Тип означает «Я хочу, чтобы это было не менее n байтов, но мне все равно, если компилятор выделяет его как больший тип, чтобы соответствовать выравниванию ".int_fastn_t
означает «я хочу, чтобы это было длиной n байтов, но если это заставит мой код работать быстрее, компилятор должен использовать больший тип, чем указано».Как правило, различные типы stdint.h гораздо лучше, чем обычные и
int
т. Д., Потому что они переносимы. Намерениеint
заключалось в том, чтобы не придавать ему заданную ширину исключительно для того, чтобы сделать его переносимым. Но на самом деле портировать его сложно, потому что вы никогда не знаете, насколько он велик в конкретной системе.источник
В зависимости от того, как работает конкретная операционная система, вы обычно ожидаете, что память будет выделена неоптимизированной, так что когда вы вызываете байт или слово или какой-то другой небольшой тип данных, значение занимает весь регистр, все это очень собственный. Однако то, как ваш компилятор или интерпретатор работает, чтобы интерпретировать это, является чем-то другим, поэтому, если вы, например, должны были скомпилировать программу на C #, значение может физически занимать регистр для себя, однако это значение будет проверяться границей, чтобы гарантировать, что вы этого не сделаете попытайтесь сохранить значение, которое превысит границы предполагаемого типа данных.
С точки зрения производительности, и если вы действительно педантичны в таких вещах, вероятно, быстрее просто использовать тип данных, который наиболее точно соответствует целевому размеру регистра, но тогда вы упускаете весь этот прекрасный синтаксический сахар, который делает работу с переменными настолько простой ,
Как это поможет вам? Что ж, вам решать, для какой ситуации вы кодируете. Почти для каждой программы, которую я когда-либо писал, достаточно просто довериться компилятору, чтобы оптимизировать вещи и использовать наиболее удобный для вас тип данных. Если вам нужна высокая точность, используйте большие типы данных с плавающей точкой. Если вы работаете только с положительными значениями, вы, вероятно, можете использовать целое число без знака, но по большей части достаточно просто использовать тип данных int.
Однако если у вас есть очень строгие требования к данным, такие как написание протокола связи или какой-то алгоритм шифрования, то использование типов данных с проверкой диапазона может оказаться очень полезным, особенно если вы пытаетесь избежать проблем, связанных с переполнением / переполнением данных или неверные значения данных.
Единственная другая причина, по которой я могу подумать о том, чтобы использовать определенные типы данных, - это когда вы пытаетесь сообщить намерение в своем коде. Например, если вы используете сокращение, вы говорите другим разработчикам, что разрешаете использовать положительные и отрицательные числа в очень небольшом диапазоне значений.
источник
Как прокомментировал шарфридж , это
Попытка оптимизации использования памяти может повлиять на другие области производительности, и золотые правила оптимизации :
Чтобы узнать, настало ли время для оптимизации, требуется тестирование и тестирование. Вам нужно знать, где ваш код неэффективен, чтобы вы могли ориентироваться на свои оптимизации.
Чтобы определить, действительно ли оптимизированная версия кода на самом деле лучше, чем наивная реализация в любой момент времени, вам нужно сравнить их параллельно с теми же данными.
Кроме того, помните, что только потому, что данная реализация более эффективна на процессорах текущего поколения, это не значит, что так будет всегда . Мой ответ на вопрос Важна ли микрооптимизация при кодировании? подробный пример из личного опыта, когда устаревшая оптимизация привела к замедлению на порядок.
На многих процессорах доступ с невыровненной памятью значительно дороже, чем доступ с согласованной памятью. Упаковка пары шортов в вашу структуру может означать, что ваша программа должна выполнять операцию упаковки / распаковки каждый раз, когда вы касаетесь любого из этих значений.
По этой причине современные компиляторы игнорируют ваши предложения. Как ники комментарии:
Второй угадать ваш компилятор на свой страх и риск.
Есть место для такой оптимизации при работе с терабайтными наборами данных или встроенными микроконтроллерами, но для большинства из нас это не представляет особой проблемы.
источник
Это неверно Вы не можете делать предположения о том, сколько байтов содержит каждый тип, кроме
char
одного байта и не менее 8 бит на байт, при этом размер каждого типа больше или равен предыдущему.Преимущества производительности невероятно малы для переменных стека - они, скорее всего, будут выровнены / дополнены в любом случае.
Из-за этого
short
иlong
практически не используются в наше время, и вы почти всегда лучше использоватьint
.Конечно, есть и то,
stdint.h
что идеально подходит для использования, когдаint
его не режут. Если вы когда-либо выделяете огромные массивы целых чисел / структур, этоintX_t
имеет смысл, так как вы можете быть эффективными и полагаться на размер шрифта. Это совсем не преждевременно, так как вы можете сэкономить мегабайты памяти.источник
long
может отличаться отint
. Если ваш компилятор LP64,int
32-битный иlong
64-int
битный, и вы обнаружите, что s все еще может быть выровнен на 4 байта (например, мой компилятор).int64_t
int32_t
,int_fast32_t
Иlong
все хорошие варианты,long long
просто расточительно, иint
непереносимой.Это будет с точки зрения ООП и / или корпоративного / прикладного подхода и может быть неприменимо в определенных областях / областях, но я хочу поднять понятие примитивной одержимости .
Хорошая идея - использовать разные типы данных для разных видов информации в вашем приложении. Однако, вероятно, НЕ рекомендуется использовать встроенные типы для этого, если у вас нет серьезных проблем с производительностью (которые были измерены и проверены и т. Д.).
Если мы хотим смоделировать температуру в Кельвинах в нашем приложении, мы МОЖЕМ использовать
ushort
илиuint
или что-то подобное, чтобы обозначить, что «понятие отрицательных степеней Кельвина абсурдно и ошибка логики предметной области». Идея, стоящая за этим, звучит здраво, но вы не идете до конца. Мы поняли, что у нас не может быть отрицательных значений, поэтому удобно, если мы сможем заставить компилятор убедиться, что никто не присваивает отрицательное значение температуре Кельвина. ТАКЖЕ верно, что вы не можете делать побитовые операции при температурах. И вы не можете добавить меру веса (кг) к температуре (K). Но если вы смоделируете температуру и массу какuint
s, мы можем сделать это.Использование встроенных типов для моделирования наших объектов DOMAIN неизбежно приведет к некоторому грязному коду, пропущенным проверкам и нарушенным инвариантам. Даже если тип захватывает некоторую часть сущности (не может быть отрицательной), он неизбежно пропускает другие (не может использоваться в произвольных арифметических выражениях, не может рассматриваться как массив битов и т. Д.)
Решение состоит в том, чтобы определить новые типы, которые инкапсулируют инварианты. Таким образом, вы можете убедиться, что деньги - это деньги, а расстояния - это расстояния, и вы не можете сложить их вместе, и вы не можете создать отрицательное расстояние, но вы МОЖЕТЕ создать отрицательное количество денег (или долг). Конечно, эти типы будут использовать встроенные типы внутри, но это скрыто от клиентов. Относительно вашего вопроса о производительности / потреблении памяти, такого рода вещи могут позволить вам изменить внутреннее хранение вещей, не меняя интерфейс ваших функций, которые работают на ваших доменных объектах, если вы обнаружите, что чертовски
short
мало большой.источник
Да, конечно. Рекомендуется использовать
uint_least8_t
для словарей, огромных массивов констант, буферов и т. Д. Лучше использоватьuint_fast8_t
для целей обработки.uint8_least_t
(хранение) ->uint8_fast_t
(обработка) ->uint8_least_t
(хранение).Например, вы берете 8-
source
битный символ , 16-битные кодыdictionaries
и некоторые 32-битныеconstants
. Чем вы обрабатываете 10-15 битные операции с ними и выводите 8 битныеdestination
.Давайте представим, что вам нужно обработать 2 гигабайта
source
. Количество битовых операций огромно. Вы получите отличный бонус производительности, если во время обработки переключитесь на быстрые типы. Быстрые типы могут быть разными для каждого семейства процессоров. Вы можете включатьstdint.h
и использоватьuint_fast8_t
,uint_fast16_t
,uint_fast32_t
и т.д.Вы можете использовать
uint_least8_t
вместоuint8_t
переносимости. Но на самом деле никто не знает, какой современный процессор будет использовать эту функцию. VAC машина - музейный экспонат. Так что, возможно, это перебор.источник