Плюсы / минусы использования char для маленьких целых чисел в C - PullRequest
5 голосов
/ 06 декабря 2009

Есть ли недостаток в использовании 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, несмотря на то, что в моих тестах это, по крайней мере, показалось медленнее. Таким образом, мораль истории, как справедливо предположил Кристоф: всегда ориентир!

Ответы [ 6 ]

12 голосов
/ 06 декабря 2009

C99 добавил так называемые «самые быстрые» целочисленные типы минимальной ширины для решения этой проблемы. Для диапазона, который вас интересует, типы будут int_fast8_t и uint_fast8_t, которые можно найти в stdint.h.

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

6 голосов
/ 06 декабря 2009

Что ж, первая проблема заключается в том, что в стандарте C не определено, является ли обычный char со знаком или без знака - поэтому единственный диапазон, на который вы можете положиться, - от 0 до 127.

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

Обратите внимание, что операнды, меньшие int, расширяются либо до int, либо до unsigned int во время вычисления выражения.

3 голосов
/ 06 декабря 2009

Арифметика на символах почти наверняка будет выполняться с использованием тех же регистров, что и на арифметике на целых. Например:

char c1 = 1;
char c2 = c1 + 2;

Дополнение компилируется с помощью VC ++:

00401030   movsx       eax,byte ptr [ebp-4]
00401034   add         eax,2
00401037   mov         byte ptr [ebp-0Ch],al

где eax - это 32-битный регистр.

Таким образом, при использовании арифметических вычислений преимущества использования символов над целыми числами отсутствуют.

3 голосов
/ 06 декабря 2009

Еще один минус, о котором я могу подумать, это то, что (насколько я знаю) «современные» процессоры выполняют всю свою математику в «полных» целых числах, как правило, в 32 битах. Таким образом, работа с char обычно означает удаление одного байта из памяти, заполнение нулями при передаче в регистр, выполнение чего-либо с ним и последующее сжатие в память только самых младших битов результата. Особенно, если char не выровнен на удобной границе, этот доступ к памяти требует гораздо больше работы.

Использование char для int действительно полезно только тогда, когда у вас есть лот чисел (то есть большой массив) и вам нужно сэкономить место.

2 голосов
/ 06 декабря 2009

Внутренне процессоры обычно выполняют арифметику над машинными словами. Это означает, что при выполнении вычислений для других типов, хотя само вычисление будет занимать одинаковое время, в зависимости от доступного набора команд может потребоваться дополнительная работа для считывания входных данных и приведения результатов вычислений в целевой тип (например, расширение знака / заполнение нулями, смещение / маскирование, чтобы избежать несогласованного доступа к памяти и т. д.).

Именно поэтому C определяет типы и операции так, как он это делает - размер int не является обязательным для стандарта, что позволяет авторам компилятора привести его в соответствие с машинным словом, а оценка выражений определяется для продвижения меньших целочисленных типов. до int, значительно уменьшая количество точек, в которых результаты должны быть приведены к какому-либо типу цели.

Допустимыми причинами использования char для хранения целочисленных значений являются случаи, когда пространство действительно имеет такое большое значение (не так часто, как вы думаете), и при описании какого-либо внешнего формата данных / протокола, по которому вы собираете данные в / из. Ожидайте использования char, чтобы понизить небольшую потерю производительности, особенно на оборудовании, таком как Cell SPU, где доступны только обращения к памяти машинного слова, поэтому для доступа к символу в памяти требуется несколько смен и масок.

0 голосов
/ 06 декабря 2009

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

typedef char REALLYSHORT;

Таким образом, А) Понятно, что вы делаете, и Б) Вы можете легко изменить его (например, только в одном месте), если у вас возникнут проблемы.

У вас есть действительно веская причина не использовать int?

...