Printf() форматирование для hex

Это более любопытный запрос, чем важный вопрос, но почему при печати шестнадцатеричного числа с 8-значным номером с ведущими нулями этот %#08X не отображает тот же результат, что и 0x%08X?

Когда я пытаюсь использовать первое, флаг форматирования 08 удаляется, и он не работает только с 8.

Снова мне было просто любопытно.

Ответ 1

Часть # дает вам 0x в выходной строке. 0 и x подсчитываются против ваших символов "8", перечисленных в части 08. Вам нужно задать 10 символов, если вы хотите, чтобы они были одинаковыми.

int i = 7;

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

Также, изменяя случай x, влияет на оболочку выводимых символов.

printf("%04x", 4779); // gives 12ab
printf("%04X", 4779); // gives 12AB

Ответ 2

"0x" подсчитывается к восьмизначному счету. Вам нужно "%#010x".

Обратите внимание, что # не добавляет 0x к 0 - результат будет 0000000000 - так что вы, вероятно, должны просто использовать "0x%08x" в любом случае.

Ответ 3

Преобразованию %#08X должно предшествовать значение с 0X; это требуется стандартом. В стандарте нет никаких доказательств того, что символ # должен изменять поведение части спецификации 08 за исключением того, что префикс 0X считается частью длины (так что вы можете/должны использовать %#010X. Если, как и я, вам нравится ваш гекс, представленный как 0x1234CDEF, тогда вы должны использовать 0x%08X для достижения желаемого результата. Вы можете использовать %#.8X и это также должно вставить ведущие нули.

Попробуйте варианты в следующем коде:

#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);
}

На машине с RHEL 5, а также на Mac OS X (10.7.5) вывод был:

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

Я немного удивлен лечением 0; Я не понимаю, почему префикс 0X опущен, но с двумя отдельными системами это должно быть стандартным. Это подтверждает мои предубеждения против опции #.


Обработка нуля в соответствии со стандартом.

ISO/IEC 9899: 2011 §7.21.6.1 Функция fprintf

Characters6 Знаки флага и их значения:
...
# Результат конвертируется в "альтернативную форму".... Для преобразования x (или X) ненулевой результат имеет префикс 0x (или 0X)....

(Акцент добавлен.)


Обратите внимание, что использование %#X будет использовать заглавные буквы для шестнадцатеричных цифр и 0X в качестве префикса; использование %#x будет использовать строчные буквы для шестнадцатеричных цифр и 0x в качестве префикса. Если вы предпочитаете 0x в качестве префикса и заглавных букв, вы должны кодировать 0x отдельно: 0x%X Конечно, при необходимости можно добавлять другие модификаторы формата.

Для печати адресов используйте заголовок <inttypes.h> тип uintptr_t и PRIXPTR формата PRIXPTR:

#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;
}

Пример вывода:

Address 0x7FFEE5B29428

Выбери свой яд по длине - я считаю, что точность 12 хорошо работает для адресов на Mac под управлением MacOS. В сочетании с . чтобы указать минимальную точность (цифры), он надежно форматирует адреса. Если вы установите точность до 16, дополнительные 4 цифры всегда будут равны 0 в моем опыте на Mac, но, безусловно, есть смысл использовать 16 вместо 12 в переносимом 64-битном коде (но вы бы использовали 8 для 32-битный код).