Я смотрю на следующий код:
#include <stdio.h>
#include <limits.h>
bool
writebytes (unsigned long long x, int nbytes)
{
do
{
if (putchar (x) < 0)
return false;
x >>= CHAR_BIT;
nbytes--;
}
while (0 < nbytes);
return true;
}
И это работает (написано моим профессором).
Я понимаю, что он выводит все nbytes из unsigned long long x на экран, и как он это делает. Мой единственный вопрос: почему в C вы можете передать unsigned long long функции, которая принимает char в качестве параметра putchar(int char), и она все равно интерпретирует его правильно?
Захватывает ли C только первый CHAR_BIT переданного параметра? Почему нет необходимости в кастинге, например:
Putchar( (char) x )
putchar()
принимает int, а не char. Однако применяются те же правила преобразования.
(что, если я правильно понял, преобразование большего целочисленного типа в меньший тип со знаком определяется реализацией, если только преобразуемое значение уже не вписывается в диапазон меньшего типа. Внутренне putchar() преобразует свой аргумент int в беззнаковый char, который хорошо определен, но переход от unsigned long long к int first не является)
Неявное преобразование unsigned long long в int может привести к переполнению (т. е. если оно не может быть представлено новым типом). Я считаю, что поведение, когда это происходит, определяется реализацией и может привести к поднятию сигнала.
putchar(int char)
Параметр putchar является int. Типа нет int char.
В putchar(x) unsigned long long x преобразуется в тип параметра int согласно C 2018 6.5.2.2 7. Если значение x не может быть представлено в типе int, результатом является значение или сигнал, определяемый реализацией, согласно C 2018 6.3. .1.3 3. Обычные современные реализации C переносят значение по модулю INT_MAX+1, что эквивалентно взятию младших n байтов, если используется дополнение до двух, где n — количество байтов в int.
C 2018 7.21.7.8, 7.21.7.7 и 7.21.7.3 указано, что putchar записывает символ, указанный путем преобразования его параметра в unsigned char. Это преобразование перенесет значение по модулю UCHAR_MAX+1, что эквивалентно взятию младшего байта.
Таким образом, в большинстве современных реализаций C putchar(x) будет записывать младший байт x в стандартный вывод.
Затем x >>= CHAR_BIT; сдвигает байты в x на один байт вниз, и цикл повторяется, чтобы записать nbytes байт.
Изменение putchar (x) на putchar((unsigned char) x) улучшит переносимость за счет удаления определяемого реализацией преобразования в int.
Я не верю, что этот код гарантированно сработает. Он может работать на определенной платформе, с определенным компилятором и библиотеками, но это плохое основание для того, чтобы считать что-то "правильным".