Agnóstico endian C (gcc) , sem bibliotecas padrão, 92 91 bytes
h(n)é uma função inteira de um dígito-> hexadecimal.
f(x,p)pega um número inteiro e um char[8]ponteiro. O resultado são 8 bytes de chardados. ( Não é terminado em 0, a menos que o chamador faça isso.)
Pressupostos: conjunto de caracteres ASCII. O complemento de 2, de intmodo que a mudança para a direita eventualmente reduz o bit de sinal e a conversão de uint32_tpara intnão altera o padrão de bits se o bit alto estiver definido. inttem pelo menos 32 bits. (A Wider pode deixá-lo funcionar nas implementações de complemento 1 ou de magnitude C de sinal).
Não-premissas: qualquer coisa sobre a implementação de ordem de bytes ou assinatura de 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);}
Experimente online! incluindo o chamador de teste usando printf("%.8s\n", buf)para imprimir o buffer de saída sem terminá-lo 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);
}
Fazer n&=15;dentro h(x)é o ponto de equilíbrio; 6 bytes lá vs. 3 cada um para &15isolar a mordidela baixa nos dois sites de chamada.
,é um ponto de sequência (ou equivalente na terminologia moderna), portanto, é seguro fazer *p++= stuffduas vezes em uma instrução quando separado pelo ,operador.
>>no número inteiro assinado é definido como implementação aritmético ou lógico. O GNU C o define como complemento da aritmética 2. Mas em qualquer máquina de complemento de 2, isso realmente não importa, porque nunca olhamos para os 0s ou cópias do bit de sinal. O MSB original acabará inalterado no byte baixo. Este não é o caso do sinal / magnitude e não tenho certeza sobre o complemento de 1.
Portanto, isso pode ser portável apenas para as implementações C do complemento 2. (Ou onde inté maior que 32 bits, o bit 31 é apenas parte da magnitude.) A conversão não assinada -> assinada também modifica o padrão de bits para números inteiros negativos, de modo que, &15em um intsó, extrairíamos petiscos do valor não assinado original no complemento de 2. Novamente, a menos que intseja maior que 32 bits, todas as entradas são não negativas.
A versão com golf tem UB de cair no final de uma função não nula. Não para retornar um valor, apenas para evitar declará-lo em voidvez do padrão int. Compiladores modernos quebram isso com a otimização ativada.
Motivação: eu estava pensando em uma resposta x86 ou ARM Thumb asm, pensei que poderia ser divertido fazê-lo manualmente em C, talvez para asm gerado por compilador como ponto de partida. Consulte /programming/53823756/how-to-convert-a-number-to-hex para obter a velocidade x86 asm com eficiência de velocidade, incluindo uma versão AVX512VBMI com apenas duas instruções (mas precisa de vetores de controle para vpmultishiftqb e vpshufb então não seria ótimo para o golfe). Normalmente, é necessário um trabalho extra para o SIMD inverter pela ordem de impressão no x86 little-endian, portanto essa saída hexadecimal invertida é realmente mais fácil do que o normal.
Outras ideias
Eu considerei pegar o número inteiro por referência e fazer um loop sobre seus bytes com char*uma implementação C de little endian (como x86 ou ARM). Mas não acho que isso economizaria muito.
Usando sprintfpara executar 1 byte por vez, 64 bytes após jogar golfe:
int i;
void f(x,p)char*p;{
for(i=4;sprintf(p,"%.2x",x&255),--i;x>>=8)
p+=2;
}
Mas, se estivermos usando funções do tipo printf, é melhor trocar por byte e fazer um %xprintf da coisa toda, como a resposta do @ JL2210 .