Почему strcmp возвращает int, но не char?
Насколько я знаю, единственная разница между типами переменных, такими как char
, int
и т.д., - это объем памяти, который они занимают. Я предполагаю, что они не играют никакой роли в регулировании того, что представляет собой переменная, которую они держат. Если это правда, в здесь, я видел следующее для strcmp
:
Функция strcmp сравнивает строку s1 с s2, возвращая значение, которое имеет тот же знак, что и разница между первым различной пары символов (интерпретируемых как неподписанные char объекты, затем продвигается до int).
Я хочу спросить, почему результат продвигается до int
? Поскольку char
сравниваются, их различие во всех случаях соответствует char
. Так не продвигает ли результат int
просто добавляя связку 0 в конце результата? Итак, почему это сделано?
Ответы
Ответ 1
char
может быть или не быть подписано. strcmp
должен возвращать подписанный тип, так что он может быть отрицательным, если разница отрицательна.
В более общем плане int
является предпочтительным для передачи и возврата простых числовых значений, поскольку он определен как "естественный" размер для таких значений, а на некоторых платформах более эффективен для работы с меньшими типами.
Ответ 2
Конечно, несмотря на возможность переполнения, о которой упоминали другие, он должен только иметь возможность вернуться, например. -1, 0 или 1 - которые легко вписываются в подписанный char. Реальная историческая причина этого заключается в том, что в исходной версии C в 1970-х годах функции не могли вернуть char, и любая попытка сделать это привела к возврату int.
В этих ранних компиляторах int также был типом по умолчанию (многие ситуации, в том числе возвращаемые значения функций, как видно из основного ниже, позволили вам объявить что-то как int без фактического использования ключевого слова int), поэтому имеет смысл определить любой функция, которая специально не требовала возврата другого типа, возвращающего int.
Даже сейчас, char возвращает просто знак - расширяет значение в регистр возврата int (r0 на pdp11, eax на x86). Рассмотрение его как char не принесло бы каких-либо преимуществ в производительности, в то время как позволяя ему быть фактическим различием, а не заставлять его быть -1 или 1, имело небольшое преимущество в производительности. И аксикальный ответ также указывает на то, что в любом случае его нужно было бы вернуть обратно в int, для оператора сравнения. Причиной этих рекламных акций является также историческое, кстати, это было так, что компилятору не приходилось выполнять отдельные операторы для каждой возможной комбинации char и int, тем более, что инструкции сравнения на многих процессорах работают только с int.
Доказательство. Если я создаю тестовую программу для Unix V6 для PDP-11, тип char игнорируется и возвращается целое значение вне диапазона:
char foo() {
return 257;
}
main() {
printf("%d\n", foo());
return 0;
}
# cc foo.c
# a.out
257
Ответ 3
AFAIK, стандартная библиотека C не имеет единственной функции, которая принимает или возвращает значения типа char
. У него есть аргументы и возвращаемые типы типа char*
или const char*
, но не простые char
.
Посмотрите пример в int isalpha(int c);
для более шокирующего экземпляра.
Я не знаю почему, но могу догадаться. Возможно, это связано с ABI. В любом из ABI, я знаю, что любой аргумент или возвращаемое значение типа char
вовремя продвигается до int
, поэтому нет смысла делать это. Это делает код менее эффективным, так как вам нужно будет делать усечение каждый раз, когда используется функция.
Ответ 4
Одна из возможных причин, по которым strcmp()
поддерживает значения, возвращаемые в int
, заключается в том, чтобы сохранить инструкцию процессора в вызывающем коде.
Обычно (всегда?) значение, возвращаемое strcmp()
, используется с оператором сравнения .
Посмотрим, что происходит с операндами операторов сравнения.
Обычные арифметические преобразования
Аргументы следующих арифметических операторов подвергаются неявным преобразованиям с целью получения общего реального типа, который является типом, в котором выполняется вычисление:
- двоичная арифметика
*
, /
, %
, +
, -
- реляционные операторы
<
, >
, <=
, >=
, ==
, !=
- бинарная побитовая арифметика
&
, ^
, |
- условный оператор
?:
...
4) В противном случае оба операнда являются целыми числами. В этом случае
Прежде всего, оба операнда проходят целые рекламные акции.
...
(источник: http://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions)
Целочисленные акции
Целочисленное продвижение - это неявное преобразование значения любого целочисленного типа с рангом, меньшим или равным рангам int или битового поля типа _Bool, int, signed int, unsigned int, к значению типа int
или unsigned int
.
(источник: http://en.cppreference.com/w/c/language/conversion#Integer_promotions)
Вернуться к strcmp()
Как вы можете видеть из приведенных выше цитат, возможное значение char
, возвращаемое strcmp()
, в любом случае повышается до int
.
Почему создатели C решили вернуть int
?
По очень простой причине: потому что продвижение будет происходить в любом случае и потому что (по крайней мере) требуется одна процессорная инструкция для выполнения продвижения, тем удобнее добавить эту инструкцию в код strcmp()
(т.е. в одно место), чем везде вызывается функция strcmp()
.
В 70-х годах как память, так и процессор были очень ценными ресурсами. Оптимизация, которая теперь кажется незначительной (несколько байтов памяти, сохраненных здесь и там, может быть, в нескольких десятках мест в коде) было тогда гораздо более важным.
Обновление:
С другой стороны, я думаю, что исторические причины, предоставленные этим ответом и этот ответ, больше чем мой.