Почему один printf () в C не может печатать два 64-битных значения одновременно? - PullRequest
8 голосов
/ 28 июля 2011

Я работаю в 32-битной системе. Когда я пытаюсь напечатать более одного 64-битного значения в одном printf, он не может печатать больше (т. Е. 2-го, 3-го, ...) значений переменных.

пример:

uint64_t a = 0x12345678;
uint64_t b = 0x87654321;
uint64_t c = 0x11111111;

printf("a is %llx & b is %llx & c is %llx",a,b,c);

Почему этот printf не может распечатать все значения?

Я изменяю свой вопрос

printf("a is %x & b is %llx & c is %llx",a,b,c);

, выполнив этот результат: a равно 12345678, а b равно 8765432100000000 и c равно 1111111100000000

Если я не печатаю значение a должным образом, то почему другие значения подлежат изменению ??

Ответы [ 5 ]

14 голосов
/ 28 июля 2011

Вы должны использовать макросы, определенные в <inttypes.h>

printf("a is %"PRIx64" & b is %"PRIx64" & c is %"PRIx64"\n",a,b,c);

Это чертовски уродливо, но портативно. Это было введено в C99, поэтому вам нужен C99-совместимый компилятор.

11 голосов
/ 28 июля 2011

Вам необходимо использовать правильный формат:

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

int main(void)
{
    uint64_t a = 0x12345678;
    uint64_t b = 0x87654321;
    uint64_t c = 0x11111111;

    printf("a is %#" PRIx64
            " & b is %#" PRIx64
            " & c is %#" PRIx64 "\n",
            a, b, c);
    return EXIT_SUCCESS;
}

Вывод:

a is 0x12345678 & b is 0x87654321 & c is 0x11111111
2 голосов
/ 28 июля 2011

Он печатает их все на моем компьютере, но есть три предупреждения времени компиляции, поскольку %llx ожидает long long unsigned int.

Вы уверены, что вам нужно использовать 64-битные типы? Все три ваших шестнадцатеричных кода - только 32 бита. Может быть, вы могли бы просто использовать 32 бита и сделать:

unsigned int a = 0x12345678;
unsigned int b = 0x87654321;
unsigned int c = 0x11111111;

printf("a is %x & b is %x & c is %x",a,b,c);

(или использовать стандартный stdint 32-битного unsigned int)

Если вам не нужно, чтобы они были 64-битными, чтобы вы могли добавить к ним больше битов позже.

1 голос
/ 10 февраля 2017

При необходимости для форума с именем Переполнение стека причина неожиданного вывода printf() связана с смещением стека.Несоответствие размера между спецификацией преобразования %x и аргументом функции a вызывает смещение.

При компиляции оператора

printf("a is %x & b is %llx & c is %llx",a,b,c);

компилятор генерирует машинный код, который помещает аргументы функции встек в порядке справа налево.

Компилятор использует объявления переменных, а не строку формата, для определения размера данных каждого аргумента в стеке (за исключением, возможно, генерации предупреждений).В процессоре x86 (как и на большинстве машин) указатель стека уменьшается с каждым нажатием.Поэтому при входе в библиотечную функцию printf() стек имеет следующую компоновку:

    00A4: ...

    00A0: 00000000
    009C: 11111111  Variable 'c' pushed on the stack as uint64

    0098: 00000000
    0094: 87654321  'b' pushed on the stack as uint64

    0090: 00000000
    008C: 12345678  'a' pushed on the stack as uint64

    0088: <pointer to format string>
    0084: <return address>

В этом примере произвольно указан адрес вершины стека 0084.

Поскольку все трипеременные объявлены как uint64_t, скомпилированный код помещает эти переменные в стек как 64-битные значения.Для машин с прямым порядком байтов, таких как процессор x86, старшие байты каждого значения uint64 заканчиваются старшими адресами.

Реализация printf() использует строку формата для определения числа иразмеры аргументов в стеке.В отличие от компилятора, printf() не получает информации об исходных объявлениях переменных.Первая спецификация преобразования - %x, поэтому printf() ожидает, что a будет 32-разрядным значением, и поэтому printf() анализирует макет стека следующим образом:

    00A4: ...

    00A0: 00000000

    009C: 11111111
    0098: 00000000  '%llx' reads 'c' as uint64, but from the wrong address

    0094: 87654321
    0090: 00000000  '%llx' reads 'b' as uint64, but from the wrong address

    008C: 12345678  '%x' causes printf() to read 'a' as a uint32

    0088: <pointer to format string>
    0084: <return address>

Смещение стекаобъясняет, почему a печатает 12345678, как и ожидалось, но b и c были эффективно сдвинуты влево на 32 бита до 8765432100000000 и 1111111100000000.

Исправление первой %x спецификации преобразования или аргумента приведения a до uint32 должны решить проблему.

0 голосов
/ 25 марта 2013

Использование:

"%lli" for int64_t
"%llu" for uint64_t
"%llx" for hex
"%llX" for HEX

Загляните внутрь "inttypes.h".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...