C11 неявное преобразование символов, x % y

In C11,

char foo(char x, char y) {
    return x % y;
}

Выполняется ли где-нибудь неявное преобразование (например, повышение до int)?


c
person sinelaw    schedule 28.06.2017    source источник
comment
Происходит обычное арифметическое преобразование. Возможно, вы могли бы уточнить, почему вы спрашиваете об этом? Какая у тебя проблема на самом деле?   -  person Some programmer dude    schedule 28.06.2017
comment
Alo, чтобы добавить, ....The operands of the % operator shall have integer type...so, применяется целочисленное правило продвижения.   -  person Sourav Ghosh    schedule 28.06.2017
comment
sizeof (x % y) должен дать подсказку.   -  person Ry-♦    schedule 28.06.2017
comment
@Someprogrammerdude, обычное арифметическое преобразование говорит, что если оба операнда имеют одинаковый тип, то дальнейшее преобразование не требуется, поэтому ответ ничего не происходит?   -  person sinelaw    schedule 28.06.2017
comment
@sinelaw Проверьте случай 4 в связанной ссылке: прежде всего, оба операнда подвергаются целочисленным повышениям. Если типы совпадают, это после повышения.   -  person Some programmer dude    schedule 28.06.2017
comment
@Someprogrammerdude, да, я пропустил эту часть. Таким образом, ответ заключается в том, что операнды преобразуются в int (или unsigned int) в x % y   -  person sinelaw    schedule 28.06.2017
comment
В качестве дополнительного вопроса о -Wconversion в GCC см. " title="почему gccs wconversion ведет себя по-разному для char и unsigned char"> stackoverflow.com/questions/44795474/   -  person sinelaw    schedule 28.06.2017
comment
В основном код эквивалентен return (char)((int)x % (int)y);   -  person Lundin    schedule 28.06.2017
comment
@Lundin Хороший глаз - 3 конверсии.   -  person chux - Reinstate Monica    schedule 28.06.2017


Ответы (3)


Обычные арифметические преобразования применяются к операндам % так же, как они применяются к операндам других мультипликативных и аддитивных операторов (см. 6.5.5 Мультипликативные операторы).

Операнды повышаются либо до int, либо до unsigned int, в зависимости от диапазона типа char на вашей платформе (см. 6.3.1.8 Обычные арифметические преобразования и 6.3.1.1 Булевы значения, символы и целые числа)

На большинстве реальных платформ операнды будут повышены до int, поскольку диапазон int обычно покрывает полный диапазон char. На более или менее экзотических платформах, где sizeof(char) == sizeof(int) и char являются беззнаковыми типами (подразумевая, что диапазон char не вписывается в диапазон int), они будут повышены до unsigned int.

person AnT    schedule 28.06.2017
comment
sizeof(char) = 1 в любой реализации. - person alinsoar; 28.06.2017
comment
@alinsoar: Да, это правда. И какой смысл вы пытаетесь сделать? То, что я сказал выше, подразумевает, что возможно иметь sizeof(char) == sizeof(int) == 1. В этом нет ничего плохого. - person AnT; 28.06.2017
comment
@alinsoar: я не сразу вижу актуальность или важность этого факта в этом контексте. - person AnT; 28.06.2017
comment
забудь, все нормально. - person alinsoar; 28.06.2017
comment
вы видели какую-нибудь машину, где sizeof(int) = 1 ? Как вы можете понять любую такую ​​машину? - person alinsoar; 28.06.2017
comment
@alinsoar: реализации C для встроенных платформ на процессорах TI (Texas Instruments) обычно обладают этим свойством. На первый взгляд это довольно экзотично, но именно для этого язык C был разработан с самого первого дня. Я не вижу никаких проблем, чтобы понять это. Почему? - person AnT; 28.06.2017
comment
Пока это самый правильный ответ ... можете ли вы процитировать разделы стандарта? В черновике N1570 это 6.5.5 (%), 6.3.1.8 (обычное арифметическое преобразование) и 6.3.1.1 (целочисленное продвижение). - person sinelaw; 28.06.2017
comment
@alinsoar: см., например, этот, downloads.ti.com/docs/esd/SPRU514/index.html#SPRU514N_HTML/ - person AnT; 28.06.2017
comment
предположим, у вас есть машина с размером char = 16 бит и размером int = 20 бит. Как узнать sizeof(int) ? - person alinsoar; 28.06.2017
comment
и небольшой комментарий - не всегда он повышается до int, как я ответил, если интерпретатор может доказать, что результат будет таким же, нет необходимости вычислять его с помощью принуждения. - person alinsoar; 28.06.2017
comment
@alinsoar: В C идея состоит в том, чтобы использовать минимальную адресуемую единицу памяти как char. Если минимальная адресуемая единица памяти вашей машины имеет 16 бит, это будет означать, что следующий больший тип будет иметь по крайней мере 32 бита. Единственный способ иметь 20-битный int на такой машине — это зарезервировать для него два байта (32 бита, sizeof(int) == 2), а затем зарезервировать 12 бит в качестве неиспользуемых битов заполнения. - person AnT; 28.06.2017
comment
Я думал так же - я думаю, что это действительно происходит на некоторых машинах, на некоторых таких машинах the padding пространство может генерировать представления-ловушки, поэтому интерпретатор иногда должен учитывать заполнение. - person alinsoar; 28.06.2017
comment
@alinsoar: Какие бы языковые функции ни существовали в C, все они подчиняются хорошо известному правилу оптимизации «как будто». Все языковые функции концептуальны. Компиляторы C не обязаны реализовывать их буквально. Компиляторы C должны воспроизводить только требуемое наблюдаемое поведение. Пока наблюдаемое поведение корректно, компиляторы могут выполнять этот расчет без продвижения. Это понятно без слов, поэтому мы обычно не упоминаем об этом в каждом ответе. - person AnT; 28.06.2017

Требование к операндам оператора %
n1570-§6.5.5(p2):

Операнды оператора % должны иметь целочисленный тип

В этом случае обычное арифметическое преобразование будет иметь место для обоих операндов, поскольку char повышается до unsigned int.

person haccks    schedule 28.06.2017
comment
char преобразуется в int или unsigned int. Размер и подпись char имеют значение. - person user694733; 28.06.2017
comment
Верно. В частности, в 6.5.5 говорится, что обычные арифметические преобразования выполняются для операндов, а в 6.3.1.8 для это говорится, что продвижение целых чисел выполняется для обоих операндов..., что означает, что они расширяются до int в Это дело. - person sinelaw; 28.06.2017
comment
@sinelaw; Да. Продвижение будет выполняться для обоих операндов. - person haccks; 28.06.2017
comment
char is promoted to int Or unsigned int -- действительно, это очень тонко. - person alinsoar; 28.06.2017

Да, char обычно повышается до int или unsigned int, но также возможно выполнять вычисления напрямую с chars, если интерпретатор может доказать, что результат будет таким же:

Цитата из Стандарта, 5.1.2.3 Program execution

11 ПРИМЕР 2 При выполнении фрагмента

char c1, c2;
/* ... */
c1 = c1 + c2;

«продвижение целых чисел» требует, чтобы абстрактная машина преобразовывала значение каждой переменной в целочисленный размер, а затем добавляла два целых числа и усекала сумму.

Provided the addition of two chars can be done without §5.1.2.3 Environment 15ISO/IEC 9899:201x Committee Draft — April 12, 2011 N1570 overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only produce the same result, possibly omitting the promotions.

person alinsoar    schedule 28.06.2017
comment
Для тех, кто оставляет педантичные комментарии под каждым ответом, вы упускаете из виду, что char будет всегда преобразовываться в int или unsigned int. Это гарантируется C11 6.3.1.1, в котором говорится, что int имеет более высокий целочисленный ранг преобразования, чем char. Разница может иметь значение. Рассмотрим char a; _Generic(+a, int: do_something());. Если char имеет тот же размер, что и int, но не преобразовано в int, то это выражение будет ошибочным, как и для long a. - person Lundin; 28.06.2017
comment
Приведенная часть относится только к оптимизации, когда результирующий тип int, полученный неявным продвижением, не используется программой, и где неявное продвижение само по себе не вызывает никаких побочных эффектов, таких как изменение подписи. Например, my_unsigned_char << 31 гарантированно вызовет неопределенное поведение. - person Lundin; 28.06.2017