formatação printf () para hex

190

Esta é uma consulta mais curiosa do que uma questão importante, mas por que, ao imprimir hexadecimal como um número de 8 dígitos com zeros à esquerda, isso %#08Xnão exibe o mesmo resultado que 0x%08X?

Quando tento usar o primeiro, o 08sinalizador de formatação é removido e não funciona apenas 8.

Mais uma vez eu estava apenas curioso.

wsmccusker
fonte
3
Você quer dizer 0x%.8X? Isso irá preencher com zeros. (o 0xé apenas um preâmbulo, mas você provavelmente já está ciente disso).
WhozCraig

Respostas:

282

A #peça fornece um 0xna string de saída. A contagem 0e os xcaracteres "8" listados na 08parte. Você precisa pedir 10 caracteres se quiser que seja o mesmo.

int i = 7;

printf("%#010x\n", i);  // gives 0x00000007
printf("0x%08x\n", i);  // gives 0x00000007
printf("%#08x\n", i);   // gives 0x000007

A alteração também de maiúsculas e minúsculas xafeta a caixa dos caracteres emitidos.

printf("%04x", 4779); // gives 12ab
printf("%04X", 4779); // gives 12AB
Mike
fonte
A linha superior gera 14F0x00000007 para mim. O segundo e terceiro trabalho, como está escrito.
Quantumpotato
@quantumpotato - Isso é ... estranho. A primeira e a terceira linhas são idênticas, com exceção do número de 0 que devem produzir. Qual foi o seu compilador / sistema / linha de código que produziu isso? Você tinha alguma linha seguindo a que foi impressa 14F?
Mike
18
Observe que i = 0;, se as versões utilizadas %#não incluirem o 0xprefixo.
amigos estão
mas e quanto ao hexadecimal: 0x43A66C31C68491C0 Tentei o seguinte: __int64 int64 = 0x43A66C31C68491C0; printf_s ("% # 15X% d", int64, int64); Mas a saída é 0XC68491C0, não 0x43A66C31C68491C0
123iamking
Sobre o hex 0x43A66C31C68491C0 acima, resolvi-o, a solução é 0x% I64X, não% # 15X #
123iamking
52

O "0x" conta para a contagem de oito caracteres. Você precisa "%#010x".

Note-se que #se não anexar o 0 x 0 - o resultado será 0000000000- então você provavelmente realmente deve apenas usar "0x%08x"de qualquer maneira.

Random832
fonte
34

A %#08Xconversão deve preceder o valor com 0X; isso é exigido pelo padrão. Não há nenhuma evidência no padrão de que isso #deva alterar o comportamento da 08parte da especificação, exceto que o 0Xprefixo é contado como parte do comprimento (então você pode querer / precisar usar %#010X. Se, como eu, você gosta do seu hexadecimal apresentado como 0x1234CDEF, você precisa usar 0x%08Xpara obter o resultado desejado.Você pode usar %#.8Xe isso também deve inserir os zeros à esquerda.

Tente variações no seguinte código:

#include <stdio.h>

int main(void)
{
    int j = 0;
    printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    for (int i = 0; i < 8; i++)
    {
        j = (j << 4) | (i + 6);
        printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    }
    return(0);
}

Em uma máquina RHEL 5 e também no Mac OS X (10.7.5), a saída era:

0x00000000 = 00000000 = 00000000 = 0000000000
0x00000006 = 0X000006 = 0X00000006 = 0x00000006
0x00000067 = 0X000067 = 0X00000067 = 0x00000067
0x00000678 = 0X000678 = 0X00000678 = 0x00000678
0x00006789 = 0X006789 = 0X00006789 = 0x00006789
0x0006789A = 0X06789A = 0X0006789A = 0x0006789a
0x006789AB = 0X6789AB = 0X006789AB = 0x006789ab
0x06789ABC = 0X6789ABC = 0X06789ABC = 0x06789abc
0x6789ABCD = 0X6789ABCD = 0X6789ABCD = 0x6789abcd

Estou um pouco surpreso com o tratamento de 0; Não sei por que o 0Xprefixo foi omitido, mas com dois sistemas separados, ele deve ser padrão. Isso confirma meus preconceitos contra a #opção.


O tratamento do zero é de acordo com o padrão.

ISO / IEC 9899: 2011 §7.21.6.1 A fprintffunção

¶6 Os caracteres da bandeira e seus significados são:
...
#O resultado é convertido em uma "forma alternativa". ... Parax (ou X) conversão, um resultado diferente de zero tem 0x(ou 0X) um prefixo para ele. ...

(Enfase adicionada.)


Observe que usar %#X usará letras maiúsculas para os dígitos hexadecimais e 0Xcomo prefixo; use %#xusará letras minúsculas para os dígitos hexadecimais e 0xcomo prefixo. Se você preferir 0xque as letras de prefixo e maiúsculas, você tem que código 0xseparadamente: 0x%X. Outros modificadores de formato podem ser adicionados conforme necessário, é claro.

Para imprimir endereços, use o <inttypes.h> cabeçalho, o uintptr_ttipo e a PRIXPTRmacro de formato:

#include <inttypes.h>
#include <stdio.h>

int main(void)
{
    void *address = &address;  // &address has type void ** but it converts to void *
    printf("Address 0x%.12" PRIXPTR "\n", (uintptr_t)address);
    return 0;
}

Exemplo de saída:

Address 0x7FFEE5B29428

Escolha seu veneno no comprimento - acho que uma precisão de 12 funciona bem para endereços em um Mac executando o macOS. Combinado com o .para especificar a precisão mínima (dígitos), ele formata os endereços de maneira confiável. Se você definir a precisão como 16, os 4 dígitos extras serão sempre 0 na minha experiência no Mac, mas certamente há um argumento a ser usado para usar 16 em vez de 12 no código portátil de 64 bits (mas você usaria 8 para Código de 32 bits).

Jonathan Leffler
fonte