Подтвердить что ты не робот

Почему С++ допускает неявное преобразование из int в unsigned int?

Рассмотрим следующий код:

void foo(unsigned int x)
{

}

int main()
{
  foo(-5);
  return 0;
}

Компиляция без проблем. Подобные ошибки могут вызвать множество проблем и их трудно найти. Почему С++ допускает такое преобразование?

4b9b3361

Ответ 1

Короткий ответ заключается в том, что C первоначально поддерживал такие преобразования, и они не хотели нарушать существующее программное обеспечение на С++.

Обратите внимание, что некоторые компиляторы будут предупреждать об этом. Например, g++ -Wconversion будет предупреждать об этой конструкции.

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

EDIT: Дополнительное вероятное объяснение: Помните, что первоначально C был гораздо более слабым, чем С++. С объявлением функции стиля K & R было бы невозможно, чтобы компилятор обнаружил такие неявные преобразования, поэтому зачем ограничивать это на языке. Например, ваш код выглядел бы примерно так:

int foo(x)
unsigned int x
{

}

int main()
{
  foo(-5);
  return 0;
}

в то время как сама декларация была бы int foo(x);

Компилятор действительно полагался на программиста, чтобы передавать правильные типы в каждый вызов функции и не делал конверсий на сайте вызова. Затем, когда фактически вызванная функция, данные в стеке (и т.д.) Интерпретировались так, как указано в объявлении функции.

После того, как был написан код, основанный на таком неявном преобразовании, было бы намного сложнее удалить его из ANSI C, даже когда были добавлены прототипы функций с фактической информацией о типе. Вероятно, поэтому он остается в C даже сейчас. Затем появился С++ и снова решил не нарушать совместимость с C, продолжая допускать такие неявные преобразования.

Ответ 2

  • Просто еще одна причуда языка, в котором много глупых причуд.
  • Преобразование четко определено для обертывания, что может быть полезно в некоторых случаях.
  • Он обратно совместим с C, что делает это по вышеуказанным причинам.

Сделайте выбор.

Ответ 3

@user168715 - это правильно. Первоначально С++ был разработан как супермножество C, притворяясь как можно более совместимым с обратной связью. Философия "С" заключается в том, чтобы доставить большую часть ответственности программисту, а не запрещать опасные вещи. Для программистов C это рай, для программистов на Java, это ад... вопрос вкуса.

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

Я также согласен с тем, что некоторые унаследованные свободы могут привести к ошибкам, которые действительно трудно отлаживать, поэтому я добавляю к сказанному, что в g++ вы можете включить предупреждение, чтобы предотвратить такую ​​ошибку: -Wconversion.

- Wконверсия

Предупреждать о неявных преобразованиях, которые могут изменить значение. Это включает конверсии между реальным и целым числом, как abs (x), когда x является двойным; конверсии между подписанными и unsigned, как unsigned ui = -1; а также конверсии в меньшие типы, например sqrtf (M_PI). Не предупреждайте о явных отличает абс ((int) x) и ui = (без знака) -1, или если значение не изменено путем преобразования, как в abs (2.0). Предупреждения о конверсиях между целыми знаками без знака могут быть отключены с помощью -Wno-знак-преобразование.

Для С++ также предупреждайте о запутывании разрешения перегрузки для пользовательских преобразования; и конверсии, которые будут никогда не используйте оператор преобразования типов: конверсии в пустоту, один и тот же тип, базовый класс или ссылку на них. Предупреждения о конверсиях между целые числа без знака отключен по умолчанию в С++, если -Wsign-преобразование явно включено.

Другие компиляторы могут иметь одинаковые флаги.

Ответ 4

К моменту первоначального стандарта C преобразование уже было разрешено многими (все?) компиляторами. Основываясь на обосновании C, как представляется, было мало (если есть) обсуждение вопроса о том, следует ли допускать такие неявные преобразования. К моменту появления С++ такие неявные преобразования были достаточно распространены, что устранение их привело бы к тому, что язык несовместим с большим количеством кода C. Вероятно, это сделало С++ чище; это, безусловно, сделало бы ее гораздо менее используемой - до такой степени, что она, вероятно, никогда не вышла бы за рамки "C с классами", и даже это будет просто игнорируемая сноска в истории лабораторий Bell.

Единственный реальный вопрос, стоящий на этой линии, заключался в том, что правила "сохранение значения" и "неподписанное сохранение" при продвижении значений без знака "меньше", чем int. Разница между двумя возникает, когда у вас есть (например) unsigned short, добавляемый к unsigned char.

Неподписанные правила сохранения говорят, что вы рекламируете оба беззнаковых int. Правила сохранения значений говорят, что вы рекламируете оба значения до int, если оно может представлять все значения исходного типа (например, общий случай 8-разрядного char, 16-разрядного короткого и 32-битного int). С другой стороны, если int и short являются 16 битами, поэтому int не может представлять все значения unsigned short, тогда вы продвигаете unsigned short в unsigned int (обратите внимание, что он по-прежнему считается продвижением по службе, хотя это происходит только тогда, когда оно действительно а не продвижение - т.е. два типа имеют одинаковый размер).

К лучшему или худшему (и это неоднократно аргументировалось обоими направлениями) комитет выбирал сохранение ценности, а не беззнаковое сохранение рекламных акций. Обратите внимание, однако, что это имеет дело с преобразованием в противоположном направлении: вместо того, чтобы подписаться на unsigned, это о том, конвертируете ли вы без знака в подпись.

Ответ 5

Поскольку стандарт допускает неявное преобразование из signed в unsigned.

Также (int)a + (unsigned)b приводит к unsigned - это стандарт С++.