C (gcc) agnostique endien, pas de bibliothèques standard, 92 91 octets
h(n)est une fonction d'aide à un chiffre entier> hexadécimal.
f(x,p)prend un entier et un char[8]pointeur. Le résultat est 8 octets de chardonnées. ( Pas de terminaison 0 sauf si l'appelant le fait.)
Hypothèses: jeu de caractères ASCII. Le complément de 2, intdonc le décalage vers la droite fait finalement baisser le bit de signe, et la conversion de a uint32_ten intne modifie pas le motif binaire si le bit haut est défini. intest au moins 32 bits. (Plus large pourrait le laisser fonctionner sur les implémentations du complément 1 ou de la magnitude du signe C).
Non-hypothèses: tout ce qui concerne l'ordre des octets de mise en œuvre ou la signature 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);}
Essayez-le en ligne! y compris l'appelant de test utilisant printf("%.8s\n", buf)pour imprimer le tampon de sortie sans le terminer par 0.
Non golfé:
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);
}
Faire à l' n&=15;intérieur h(x)est au seuil de rentabilité; 6 octets contre 3 chacun pour &15isoler le quartet bas sur les deux sites d'appel.
,est un point de séquence (ou équivalent dans la terminologie moderne), il est donc sûr de le faire *p++= stuffdeux fois dans une seule instruction lorsqu'il est séparé par l' ,opérateur.
>>sur un entier signé est défini par l'implémentation comme arithmétique ou logique. GNU C le définit comme complément arithmétique 2. Mais sur n'importe quelle machine complémentaire de 2, cela n'a pas vraiment d'importance car nous ne regardons jamais les 0 décalés ou les copies du bit de signe. Le MSB d'origine finira par descendre dans l'octet de poids faible inchangé. Ce n'est pas le cas sur signe / amplitude, et je ne suis pas sûr du complément de 1.
Donc, cela ne peut être portable que pour les implémentations C du complément 2. (Ou où intest plus large que 32 bits, le bit 31 n'est qu'une partie de l'ampleur.) Unsigned -> la conversion signée permet également de masquer le modèle de bits pour les nombres entiers négatifs, ainsi de &15suite un intextrait uniquement les grignotages de la valeur non signée d'origine sur le complément à 2. Encore une fois, sauf s'il intétait plus large que 32 bits, toutes les entrées sont donc non négatives.
La version golfée a UB de tomber de la fin d'une fonction non nulle. Ne pas renvoyer une valeur, juste pour éviter de la déclarer voidau lieu de la valeur par défaut int. Les compilateurs modernes briseront cela avec l'optimisation activée.
Motivation: J'envisageais une réponse asm x86 ou ARM Thumb, j'ai pensé qu'il pourrait être amusant de le faire manuellement en C, peut-être pour un asm généré par le compilateur comme point de départ. Voir /programming/53823756/how-to-convert-a-number-to-hex pour asm x86 efficace en termes de vitesse, y compris une version AVX512VBMI qui ne contient que 2 instructions (mais a besoin de vecteurs de contrôle pour vpmultishiftqb et vpshufb ne serait donc pas génial pour le golf). Normalement, il faut du travail supplémentaire pour SIMD pour inverser l'octet dans l'ordre d'impression sur le x86 peu endian, donc cette sortie hexadécimale inversée est en fait plus facile que la normale.
Autres idées
J'ai envisagé de prendre l'entier par référence et de faire une boucle sur ses octets avec char*, sur une implémentation C peu endienne (comme x86 ou ARM). Mais je ne pense pas que cela aurait sauvé beaucoup.
Utilisation sprintfde faire 1 octet à la fois, 64 octets après le golf:
int i;
void f(x,p)char*p;{
for(i=4;sprintf(p,"%.2x",x&255),--i;x>>=8)
p+=2;
}
Mais si nous utilisons des fonctions de type printf, nous pourrions aussi bien échanger des octets et faire un %xprintf de tout cela comme la réponse de @ JL2210 .