Плюсы и минусы использования char для небольших целых чисел в C
Автор вопроса: me_andОтветов: 6
Есть ли недостатки в использовании char для небольших целых чисел в C? Есть ли какие-либо преимущества, кроме выгоды от занятости/памяти?
В частности, может ли процессор справиться с целочисленной арифметикой на char лучше или хуже, чем на (long/short) int?
Я знаю, что это будет зависеть от процессора/системы/компилятора, но я надеюсь получить ответ в общем случае или, по крайней мере, в общем случае для 32-битных Windows и Solaris, поскольку это системы, над которыми я сейчас работаю. . Я также предполагаю, что такие вещи, как проблемы с переполнением/зацикливанием, уже решены.
Обновление: Visual Studio 6.0 на самом деле не имеет stdint.h, как предложил Кристоф. Небольшой бенчмаркинг в Windows (VS 6.0, отладочная сборка, 32-разрядная версия) с несколькими сложенными циклами показывает, что int и long обеспечивают аналогичную производительность, которая примерно в два раза выше, чем char. Выполнение того же теста в Linux с помощью gcc аналогично привязывает int и long к одинаковым, и оба быстрее, чем char, хотя разница менее заметна.
В качестве примечания: я не тратил много времени на поиски, но первая реализация stdint.h для VS 6.0, которую я нашел (через Wikipedia) определяет uint_fast8_t как unsigned char, несмотря на то, что по крайней мере в моих тестах это кажется медленнее. Таким образом, мораль этой истории, как справедливо подсказал Кристоф: всегда ориентируйтесь!
В C99 для решения этой проблемы были добавлены так называемые "самые быстрые" целочисленные типы минимальной ширины. Для интересующего вас диапазона это будут типы int_fast8_t и uint_fast8_t, которые можно найти в stdint.h.
Имейте в виду, что прироста производительности может не быть (увеличение потребления памяти может даже замедлить работу); как всегда показатель! Не оптимизируйте преждевременно или исключительно исходя из потенциально ошибочных предположений о том, что должно работать.
Ответ 2 · рейтинг 6 · caf
Ну, первая проблема заключается в том, что стандарт C не определяет, является ли простой char подписанным или беззнаковым, поэтому единственный диапазон, на который вы можете полагаться при переносе, - это от 0 до 127.
Кроме этого, в целом int должен быть типом, соответствующим собственному размеру слова архитектуры (но, конечно, это ничем не навязывается). Это, как правило, тип с лучшими арифметическими характеристиками, но это все, что вы можете сказать.
Обратите внимание, что операнды уже, чем int, в любом случае расширяются до int или unsigned int во время вычисления выражения.
Ответ 3 · рейтинг 3 · Carl Smotricz
Еще одна афера, о которой я могу думать, заключается в том, что (насколько я знаю) "современные" процессоры выполняют всю свою математику в "полных" целых числах, обычно 32-битных. Таким образом, работа с char обычно означает извлечение одного байта из памяти, заполнение нулями при передаче в регистр, выполнение каких-либо действий с ним, а затем сжатие только самых младших битов результата обратно в память. Особенно, если char не выровнено по удобной границе, для этого доступа к памяти требуется гораздо больше работы.
Использование char вместо int на самом деле полезно только тогда, когда у вас много чисел (т. е. большой массив) и вам нужно сэкономить место.
Ответ 4 · рейтинг 3 · Community
Арифметика с символами почти наверняка будет выполняться с использованием тех же регистров, что и арифметика с целыми числами. Например:
char c1 = 1;
char c2 = c1 + 2;
Дополнение компилируется в следующее с помощью VC++:
Поэтому нет никакого преимущества в использовании символов над целыми числами, когда дело доходит до арифметической производительности.
Ответ 5 · рейтинг 2 · moonshadow
Внутри процессоры обычно выполняют арифметические операции с машинными словами. Это означает, что при выполнении вычислений для других типов, хотя само вычисление займет такое же время, в зависимости от доступного набора команд может потребоваться дополнительная работа для чтения входных данных и приведения результатов вычислений к целевому типу (например, расширение знака/заполнение нулями, смещение/маскирование во избежание невыровненного доступа к памяти и т. д.).
Вот почему C определяет типы и операции так, как он это делает - размер int не является обязательным стандартом, что позволяет авторам компиляторов сделать его соответствующим машинному слову, а вычисление выражений определено для преобразования меньших целочисленных типов в int, что значительно сокращает количество точек, в которых результаты должны быть приведены к некоторому целевому типу.
Веские причины использовать char для хранения целочисленных значений - это когда пространство действительно имеет большое значение (не так часто, как вы могли бы подумать), а также при описании какого-либо внешнего формата данных/протокола, в который вы упорядочиваете данные. Ожидайте, что использование char приведет к небольшому снижению производительности, особенно на оборудовании, таком как Cell SPU, где доступен только доступ к памяти размером с машинное слово, поэтому для доступа к char в памяти требуется несколько сдвигов и масок.
Ответ 6 · T.J. Crowder
Главный недостаток, который я вижу, заключается в том, что ваш код использует тип, который означает одно для значений, которые означают что-то другое - например, есть семантическая проблема, которая может быть проблемой обслуживания. Если бы вы это сделали, я бы, вероятно, рекомендовал определить его тип:
typedef char REALLYSHORT;
Таким образом, А) становится понятнее, что вы делаете, и Б) вы можете легко изменить это (например, только в одном месте), если у вас возникнут проблемы.
У вас есть действительно веская причина не использовать int?