2013-02-25 2 views
18

В настоящее время я работаю с базой кода (C, C++ смешанной), предназначенной для 32-битной платформы MIPS. Процессор довольно современный (просто отметим, что у нас есть достаточная вычислительная мощность и память).Использование uint8, uint16 и т. Д.

Код базового использует типы данных, такие как uint8 [1 байтовое целое число без знака], uint16 [2 байтовое целое число без знака], UInt32 [4 байтовое целое число без знака] и т.д.

Я знаю, как использование этих Конструкции полезны при переносе кода на разные платформы.

Мои вопросы:

  1. Что такое использование/выгоды в использовании UInt16 где uint32 также будет достаточным (если есть)?

  2. Будут ли сбережения в использовании памяти при использовании более коротких типов данных (с учетом выравнивания данных)?

  3. Если вы хотите сохранить несколько байт памяти, это что-то разумное в современном оборудовании?

+2

Это зависит от того, что вы делаете с данными? Если ваше приложение сильно общается? Если вы общаетесь с текстовыми или бинарными протоколами? Или вы пишете в/из аппаратных регистров? Также помните, что даже экономя только байт здесь и там, все это накапливается и может стать довольно большой экономией при подсчете. –

+0

Согласитесь с @JoachimPileborg полностью зависит от данных. Если вы сохраняете 16 бит для каждого int, используя uint16 вместо uint32, вы вдвое сократите свои пакеты данных. Это, однако, зависит от архитектуры. Попытайтесь посмотреть, что произойдет. – mjshaw

ответ

22

Что нужно использовать/пособие при использовании uint16, где uint32 также будет достаточным (если есть)?

Если эти uint16s являются частями массивов или структур, вы можете сохранить память и, возможно, быть в состоянии обрабатывать большие наборы данных, чем с uint32s в тех же массивов или структур. Это действительно зависит от вашего кода.

Протоколы данных и форматы файлов могут использовать uint16s, и может оказаться неправильным использование uint32s. Это зависит от формата и семантики (например, если вам нужны значения для обертывания от 65535 до 0, uint16 будет делать это автоматически, пока uint32 не будет).

OTOH, если эти uint16s являются только одиночными локальными или глобальными переменными, замена их на 32-разрядные может не иметь существенной разницы, поскольку они могут занимать одно и то же пространство из-за выравнивания и передаваться как 32-битные параметры (в стеке или в регистрах) на MIPS.

Будет ли экономия на использовании памяти при использовании более коротких типов данных (с учетом выравнивания данных)?

Может быть экономия, особенно когда uint16s являются частями многих структур или элементов больших массивов.

Если это необходимо, чтобы сохранить несколько байт памяти, это что-то разумное в современном оборудовании?

Да, вы снижаете пропускную способность памяти (что всегда хорошо), и вы часто уменьшаете различные промахи кэшей (кэши данных и TLB) при работе с меньшими данными.

+0

Спасибо за четкое объяснение. – NeonGlow

+0

От ans к первому вопросу, не будут ли структуры распакованы по умолчанию? В таком случае будет ли память сохранена? – NeonGlow

+0

Может быть, если допускается порядок элементов конструкции. Если вы чередуете 4 'uint16s' с 4' uint32s' вместо 4 'uint16s', а затем 4' uint32s' (или наоборот), спасения не будет. –

1

Использование uint16_t вместо uint32_t экономит память. Это может быть также аппаратное ограничение (например, какой-то периферийный контроллер действительно отправляет 16 бит!) Однако, возможно, не стоит использовать его из-за соображений кэширования и выравнивания (вам действительно нужно ориентироваться).

+0

Спасибо.Когда я использую uint16 (вместо uint32) в коде «non hardware», скажем, как счетчик циклов цикла for, я предполагаю единственную экономию полезной памяти. Пожалуйста, поправьте меня, если я ошибаюсь. – NeonGlow

+2

Это может даже замедлить ваш код. Это зависит от оборудования. Но арифметика 16 бит не является арифметикой 32 бит (поэтому приращение 32767 дает разные результаты) –

+0

Gt it. Спасибо за объяснение. – NeonGlow

1

Какая польза от использования uint16, где uint32 также будет достаточным (если есть)?

Есть процессоры, где unsigned char - это 16-битное значение. Групповое тестирование такого кода было бы трудным без использования typedefs (uint16 - это просто typedef для соответствующего типа).

Кроме того, с использованием этих typedefs легче создавать на разных платформах без особых проблем.

Будет ли экономия на использовании памяти при использовании более коротких типов данных (с учетом выравнивания данных)?

Нет, это не точка. Если uint16 является typedef для unsigned short, то вы можете использовать unsigned short везде, но вы можете получить разные типы на разных платформах.

Конечно, использование меньшего количества уменьшит потребление памяти. Например, используя uint16 вместо uint32, но только если вы используете массивы.

Если это необходимо, чтобы сохранить несколько байт памяти, это что-то разумное в современном оборудовании?

Это зависит от платформы:

использование
  • меньше памяти, тем меньше кэш пропускает
  • если поддерживается, есть SIMD функции, которые обрабатывают 16-разрядные данные
+0

Спасибо. Я пытался отличить использование памяти между uint16 и uint32. Не между uint16 и его 'typedef'. – NeonGlow

1

Ответы на ваши вопросы сводятся к одной ключевой концепции: насколько велики данные? Если вы много хрустаете, то преимущество использования меньших типов данных очевидно. Подумайте об этом так: простое вычисление недавно открытого большинства известных премьер может привести вас к нехватке памяти на обычной рабочей станции. Само по себе номер стоит выше гигабайта только для хранения. Это не включает работу по вычислению фактического числа. Если бы вы использовали толстый тип данных вместо тонкого, вы можете посмотреть на два гигабайта вместо этого. Простейший пример, но хороший, тем не менее.

2

Ans. 1. Программное обеспечение имеет определенные требования и спецификации, которые строго требуют принимать только 8/16-бит параметра при кодировании/декодировании или некоторых других определенных целях. Таким образом, даже если вы присваиваете значение, превышающее 127, в u8, скажем, оно автоматически обрезает данные для вас.

Ans. 2. Мы не должны забывать, что наши компиляторы намного превосходят интеллектуальные, чтобы сделать оптимизацию, будь то память или сложность. Поэтому всегда рекомендуется использовать меньшую память, когда это возможно.

Ans. 3. Разумеется, экономия памяти имеет смысл в современных h/w.

1

Использование точной ширины целочисленных типов, таких как int32_t, и друзей полезно избегать ошибок расширения знака между платформами, которые имеют разные размеры для int и long. Это может произойти, например, при применении бит-масок или при смещении бит. Если вы выполняете эти операции на long, и ваш код работает для 32-разрядного long, он может сломаться для 64-разрядного long. Если, с другой стороны, вы используете uint32_t, вы точно знаете, какие результаты вы получите независимо от платформы.

Они также полезны для обмена двоичными данными между платформами, где вам нужно только беспокоиться о достоверности хранимых данных, а не о ширине бита; если вы пишете файл int64_t, вы знаете, что на другой платформе вы можете его прочитать и сохранить в int64_t. Если вы пишете long, то это 64 бит на одной платформе, вам может понадобиться long long на другой платформе, потому что long всего 32 бита.

Сохранение памяти, как правило, не является причиной, если вы говорите об очень ограниченных средах (эмбеддеда) или больших наборов данных (например, массив с 50 миллионов элементов или, например.)

3

cstdint имеет нагрузок typedef для разных целей.

  • intN_t для определенной ширины
  • int_fastN_t для самого быстрого целого числа, которое имеет по крайней мере N битов
  • int_leastN_t для наименьшее целое число, которое имеет, по меньшей мере, N битов
  • Их unsigned эквиваленты

Вы должны выбрать в зависимости от ваших обстоятельств. Хранение тысяч в std::vector и не прикладывание вычислительных вычислений? intN_t, вероятно, ваш мужчина. Нужно быстро вычислить небольшое число целых чисел? int_fastN_t, вероятно, ваш парень.

1

Необходимо проверить произведенный машинный код/​​ассемблер, чтобы убедиться в сохранности кода. В архитектуре типа RISC типичный немедленный 16-разрядный, но использование uint16_t в любом случае будет потреблять полный 32-разрядный регистр - таким образом, при использовании типов int, но использование значений вблизи нуля приведет к таким же результатам и будет более переносимым.

ИМО экономия памяти стоит на современных платформах. Более жесткий код приводит, например, к лучшее время автономной работы и более свободный UX. Однако я бы предложил микроуправление размером только при работе с (большими) массивами или когда переменная сопоставляется с каким-то реальным ресурсом HW.

пс. Компиляторы умны, но люди, которые их записывают, в настоящий момент делают их еще лучше.

+0

+1. Спасибо, что объяснили это путем сопоставления с реальными ситуациями в мире. – NeonGlow

9

Прежде всего, если у вас есть такие типы, как uint16, где они определены? Они не являются стандартными типами, поэтому они будут определены в каком-то собственном заголовке - возможно, ваши или могут быть предоставлены какой-либо сторонней библиотекой; в этом случае вы должны спросить себя, насколько переносимым этот код, и создаете ли вы зависимость, которая может не иметь смысла в каком-либо другом приложении.

Другая проблема заключается в том, что многие библиотеки (с недобросовестной ИМО) определяют такие типы с различными именами, такими как UINT16, uint16, U16 UI16 и т. Д., Что он становится скорее кошмаром, гарантирующим соглашение о типе и избегающим конфликтов имен. Если такие имена определены в, они должны идеально размещаться в пространстве имен или иметь конкретный префикс библиотеки, чтобы указать, какую библиотеку они были определены для использования, например rtos::uint16 - rtos_uint16.

Поскольку стандартная библиотека стандарта ISO C99 предоставляет стандартные типы длины бит в stdint.h, вы должны предпочесть их использование по сравнению с любыми, определенными в проприетарном или стороннем заголовке. Эти типы имеют суффикс _t, например. uint16_t. В C++ они могут быть помещены в пространство имен std:: (хотя это не задано, поскольку заголовок был введен в C99).

1] Какая польза от использования uint16, где uint32 также будет достаточным (если есть)?

Помимо моих предыдущих рекомендаций предпочесть stdint.h «s uint16_t, есть по крайней мере два законные причины для использования определенных длиной типов:

  1. Чтобы соответствовать конкретной ширине аппаратного регистра.
  2. Использовать общий и совместимый API для разных архитектур.

2] Будет ли какой-либо экономии в использовании памяти при использовании более коротких типов данных (с учетом выравнивания данных)?

Возможно, но если память не является вашей проблемой, это не является веской причиной для их использования. Стоит рассмотреть, возможно, для больших объектов данных или массивов, но применение в глобальном масштабе редко стоит усилий.

3] Если это необходимо для сохранения нескольких байтов памяти, нужно ли это сделать что-то разумное в современном оборудовании?

См. [2]. «Современное оборудование« однако не обязательно подразумевает большие ресурсы; существует множество 32-битных устройств ARM Cortex-M с использованием всего лишь нескольких Кбайт ОЗУ. Это больше касается экономии пространства, затрат и энергопотребления, чем в плане дизайна или архитектуры.

+0

Намного понятнее :). Thnx для подробного анс. – NeonGlow

+0

К сожалению, все новые типы определены в терминах типов, поведение которых определяется способами, которые редко соответствуют требованиям приложений. Например, в ARM, если переменная хранится в регистре, 'uint32_t' может быть быстрее, чем' uint16_t' при использовании не более памяти, но если она хранится в памяти, тогда 'uint16_t' может экономить память без каких-либо затрат в скорость. К сожалению, нет такого типа, который означает «Самая дешевая вещь, которая содержит номера 0-65535». – supercat

+0

@supercat: Я не совсем уверен, какова ваша точка или почему она относится к моему ответу конкретно. Кроме того * «Реально требования к подаче заявок» * действительно? Я бы предположил, что это редко * важно. Использование, которое я предположил, что они законные, не имеет ничего общего с такой микро-оптимизацией; это работа компиляторов. Однако stdint также определяет * наименьшие * ** N ** и * fast * ** N ** типы, которые потенциально обеспечивают более тонкий контроль, который вы ищете – Clifford

Смежные вопросы