В чем необходимость расширения знака?
Рассмотрим следующий фрагмент кода C -
char sum_char(char a,char b)
{
char c = a+b;
return c;
}
Это включает в себя -
- Преобразовать второй параметр в знак расширения.
- Вставить подписанный параметр расширения в стек как b.
- Преобразовать первый параметр в расширение знака.
- Вставить подписанный параметр расширения в стек как.
- Добавьте a & b, приведите результат к char и сохраните его в c.
- С снова знак продлен.
- Расширенный знак c копируется в регистр возвращаемого значения, а функция возвращается в вызывающую функцию.
- Для сохранения результата вызывающая функция снова конвертирует int в char.
Мои вопросы -
- Кто это делает?
- Зачем нужно делать так много конверсий?
- Это уменьшит / увеличит производительность машины / компилятора?
- Если это снижает производительность, что мы должны сделать, чтобы увеличить ее?
4 ответа
- Кто это делает? - В конечном счете, это процессор, который делает это; компилятор генерирует все соответствующие инструкции для процессора для выполнения преобразований
- Зачем нужно делать так много конверсий? - Преобразования необходимы для обеспечения согласованности результатов на нескольких платформах, поддерживаемых несколькими компиляторами Си.
- Это уменьшит / увеличит производительность машины / компилятора? - Это снизит производительность по сравнению с "бездействием", но никто не заметит разницу.
- Если это снижает производительность, что мы должны сделать, чтобы увеличить ее? - Ничего: если вы должны выполнять арифметические операции над
char
с, затем вы выполняете арифметические операции наchar
s. Пусть оптимизатор позаботится об удалении всех ненужных инструкций для вашей платформы. В большинстве случаев в CPU есть инструкции, которые совместимы с семантикой, необходимой для языка C, поэтому сгенерированный код будет очень коротким.
Конечно, если вам не нужно выполнять операции со знаковыми символами, вы можете выполнять операции над неподписанными символами. Это устранило значительное расширение знака.
Преобразования, которые вы описываете, выполняются только в абстрактной машине. Компилятор может сократить все это, если это приводит к тому же наблюдаемому поведению.
При включении оптимизации мой компилятор переводит это на следующий ассемблер
sum_char:
.LFB0:
.cfi_startproc
leal (%rsi,%rdi), %eax
ret
.cfi_endproc
.LFE0:
.size sum_char, .-sum_char
который является только одним дополнением (скрыт в leal
инструкция) и ret
Прыгать.
- Код при запуске. Компилятор генерирует необходимый код для реализации указанной семантики для языка программирования.
- Я не уверен, что в том, что касается "сложения", о котором вы говорите, в C нет такого требования, насколько я знаю.
- Это не имеет смысла; по сравнению с чем?
- Вы можете попробовать удалить бессмысленно
c
переменная, и просто иметьreturn (char) (a + b);
, Тем не менее, я не думаю, что в этой функции можно что-то оптимизировать. Это должно скомпилировать очень мало кода. Если вы можете сделать это встроенным, вероятно, это будет порядка 1 инструкции.
Я не уверен в деталях вашего вопроса. Вы неоднократно ссылаетесь на расширение знака без ссылки на источник; Я полагаю, вы предполагаете, что char
тип данных будет расширен, чтобы соответствовать разрядности процессора, но я не думаю, что есть какая-либо гарантия, что это уже не так.
Однако, как ответ на ваши смутные вопросы:
- Компилятор делает это в ответ на написание кода. Кто пишет код? Разработчик, я бы вообразил. Вы сделали это, когда написали вопрос.
- Если есть необходимость (поскольку вы не цитируете свой источник), я полагаю, что это так, что процессор может обрабатывать арифметику изначально.
- Технически это уменьшило бы это, но только по сравнению с теоретической машиной, которая имеет произвольную битность. Реально, это не делает никакой заметной разницы.
- При использовании типов данных, соответствующих исходной разрядности вашей архитектуры, выигрыш в производительности будет незначительным. Тем не менее, это очень мало, и, как правило, не стоит неудобств.