C (gcc) endian-агностик, без стандартных библиотек, 92 91 байт
h(n)является однозначным целым числом -> шестнадцатеричная вспомогательная функция.
f(x,p)берет целое число и char[8]указатель. Результат - 8 байтов charданных. ( Не завершается 0, если вызывающий не делает этого.)
Допущения: набор символов ASCII. 2 дополняют, intпоэтому сдвиг вправо в конечном итоге приводит к уменьшению знакового бита, и преобразование uint32_tв intне изменяет битовую комбинацию, если установлен старший бит. intпо крайней мере 32-битный. (Более широкий мог бы позволить этому работать на реализациях дополнения 1 или величины C знака).
Не предположения: что-нибудь о реализации байтового порядка или подписанности char.
i;h(n){n&=15;return n>9?n+87:n+48;}f(x,p)char*p;{for(i=5;--i;x>>=8)*p++=h(x>>4),*p++=h(x);}
Попробуйте онлайн! включая использование вызывающего теста printf("%.8s\n", buf)для печати выходного буфера без 0-его завершения.
Ungolfed:
int h(n){n&=15;return n>9 ? n+'a'-10 : n+'0';} // single digit integer -> hex
int i;
void ungolfed_f(x,p)char*p;{
for(i=5; --i; x>>=8) // LS byte first across bytes
*p++=h(x>>4), // MS nibble first within bytes
*p++=h(x);
}
Делать n&=15;внутри h(x)безубыточно; 6 байтов против 3 для каждого, &15чтобы изолировать низкий клев на обоих участках вызова.
,является точкой последовательности (или эквивалентной в современной терминологии), поэтому ее можно сделать *p++= stuffдважды в одном операторе, когда они разделены ,оператором.
>>целое число со знаком определяется реализацией как арифметического или логического. GNU C определяет его как дополнение арифметики 2. Но на любом дополнительном компьютере 2 это не имеет большого значения, потому что мы никогда не смотрим на сдвинутые 0 или копии знакового бита. Первоначальный MSB в конечном итоге перейдет в младший байт без изменений. Это не относится к знаку / величине, и я не уверен насчет дополнения 1.
Так что это может быть переносимо только на 2 дополнения Си реализации. (Или где intон шире, чем 32 бита, поэтому бит 31 является лишь частью величины). Unsigned -> знаковое преобразование также обрабатывает битовую комбинацию для отрицательных целых чисел, поэтому &15при intизвлечении только отрывки исходного значения без знака на дополнении 2. Опять же, если только он не intбыл шире 32-битного, поэтому все входы неотрицательны.
У версии для гольфа есть UB от падения незаполненной функции. Не возвращать значение, просто чтобы не объявить его voidвместо значения по умолчанию int. Современные компиляторы сломают это с включенной оптимизацией.
Мотивация: я рассматривал асм-ответ на x86 или ARM Thumb, подумал, что было бы забавно сделать это вручную в C, возможно, для сгенерированного компилятором asm в качестве отправной точки. См. Https://stackoverflow.com/questions/53823756/how-to-convert-a-number-to-hex для получения информации о быстродействующем x86 asm, включая версию AVX512VBMI, в которой всего 2 инструкции (но нужны векторы управления для vpmultishiftqb и vpshufb так что не было бы здорово для гольфа). Обычно SIMD требуется дополнительная работа для преобразования байтов в порядок печати на младшем байтовом коде x86, так что этот вывод в шестнадцатеричном виде с обращенными байтами на самом деле проще, чем обычно.
Другие идеи
Я подумал о том, чтобы взять целое число по ссылке и зациклить его байты с char*реализацией C с прямым порядком байтов (например, x86 или ARM). Но я не думаю, что это спасло бы многое.
Используется sprintfдля выполнения 1 байта за раз, 64 байта после игры в гольф:
int i;
void f(x,p)char*p;{
for(i=4;sprintf(p,"%.2x",x&255),--i;x>>=8)
p+=2;
}
Но если мы используем функции, похожие на printf, мы могли бы также поменять байты и сделать %xprintf всего этого, как ответ @ JL2210 .