Я смотрю на следующий код:
#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
.
Я не верю, что этот код гарантированно сработает. Он может работать на определенной платформе, с определенным компилятором и библиотеками, но это плохое основание для того, чтобы считать что-то "правильным".