Почему C / C ++ автоматически конвертирует типы char / wchar_t / short / bool / enum в int?

Итак, если я правильно понял, интегральное продвижение предусматривает, что: char, wchar_t, bool, enum, short типы ВСЕГДА конвертируются в int (или же unsigned int). Затем, если в выражении есть разные типы, будет применено дальнейшее преобразование.

Я хорошо понимаю это?

И если да, то мой вопрос: почему это хорошо? Зачем? Не становись char/wchar_t/bool/enum/short ненужным? Я имею в виду, например:

char c1;
char c2;
c1 = c2;

Как я уже говорил, char ВСЕГДА превращается в intв этом случае после автоматического преобразования это выглядит так:

int c1;
int c2;
c1 = c2;

Но я не могу понять, почему это хорошо, если я знаю, что char типа будет достаточно для моих нужд.

8

Решение

Конверсии, о которых вы спрашиваете, являются обычные арифметические преобразования и целочисленные акции, определено в разделе 6.3.1.8 последнего стандарта ISO C. Они применяются к операндам большинства бинарных операторов («двоичный» означает, что они принимают два операнда, такие как +, *, так далее.). (Правила схожи для C ++. В этом ответе я просто ссылаюсь на стандарт C.)

Вкратце обычные арифметические преобразования являются:

  • Если любой из операндов long doubleдругой операнд преобразуется в long double,
  • В противном случае, если любой из операндов doubleдругой операнд преобразуется в double,
  • В противном случае, если любой из операндов floatдругой операнд преобразуется в float,
  • В противном случае целочисленные акции выполняются для обоих операндов, а затем применяются некоторые другие правила, чтобы привести два операнда к общему типу.

целочисленные акции определены в разделе 6.3.1.1 стандарта С. Для типа более узкого, чем intесли тип int может содержать все значения типа, тогда выражение этого типа преобразуется в int; в противном случае он преобразуется в unsigned int, (Обратите внимание, что это означает, что выражение типа unsigned short может быть преобразован либо в int или unsigned intв зависимости от относительных диапазонов типов.)

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

short s = 2;
printf("%d\n", s);

продвигает short значение для int, Это продвижение не происходит для невариантных функций.

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

Основная причина всей этой сложности состоит в том, чтобы допустить ограниченный набор арифметических операций, доступных на большинстве процессоров. С этим набором правил все арифметические операторы (кроме операторов сдвига, которые являются частным случаем) требуются только для работы с операндами того же типа. Здесь нет short + long оператор сложения; вместо этого short операнд неявно преобразуется в long, И нет никаких арифметических операторов для типов, более узких, чем int; если добавить два short значения, оба аргумента повышены до int, принося int результат (который затем может быть преобразован обратно в short).

Некоторые процессоры могут выполнять арифметику с узкими операндами, но не все могут это делать. Без этого единого набора правил, или компиляторы должны будут эмулировать узкую арифметику на процессорах, которые не поддерживают ее напрямую, или же Поведение арифметических выражений будет зависеть от того, какие операции поддерживает целевой процессор. Нынешние правила являются хорошим компромиссом между согласованностью между платформами и эффективным использованием операций ЦП.

7

Другие решения

Типы хранения никогда не конвертируются автоматически. Вы получаете автоматическое целочисленное продвижение, как только начинаете делать целочисленную арифметику (+, -, сдвиги, …) на эти переменные.

char c1, c2; // stores them as char
char c3 = c1 + c2; // equivalent to
char c3 = (char)((int)c1 + (int)c2);
12

если я хорошо это понял, интегральное продвижение предусматривает, что: char, wchar_t, bool, enum, короткие типы ВСЕГДА конвертируются в int (или в unsigned int).

Ваше понимание верно только отчасти: короткие типы действительно повышаются до int, но только когда вы используете их в выражениях. Конвертация производится непосредственно перед использованием. Он также «отменяется», когда результат сохраняется обратно.

Способ хранения значений остается согласованным со свойствами типа, что позволяет вам контролировать способ использования памяти для переменных, которые вы храните. Например,

struct Test {
char c1;
char c2;
};

будет в четыре раза меньше, чем

struct Test {
int c1;
int c2;
};

в системах с 32-битным ints.

3

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

2

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

2

Преобразование типов происходит при выполнении арифметических операций, операций сдвига, унарных операций. Посмотрите, что стандарт говорит об этом:

C11; 6.3.1.4. Действительное число и целое число:

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

58.Целочисленные продвижения применяются только: как часть обычных арифметических преобразований, к определенным выражениям аргументов, к операндам унарного числа. +, -, а также ~ операторы и оба операнда операторов сдвига,1 как указано в их соответствующих подпунктах


1. Акцент мой.

2
По вопросам рекламы [email protected]