Почему 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-х годах как память, так и процессор были очень ценными ресурсами. Оптимизация, которая теперь кажется незначительной (несколько байтов памяти, сохраненных здесь и там, может быть, в нескольких десятках мест в коде) было тогда гораздо более важным.

Обновление:

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