Как напечатать тип int64_t в C

298

Стандарт C99 имеет целочисленные типы с размером байтов, например int64_t. Я использую следующий код:

#include <stdio.h>
#include <stdint.h>
int64_t my_int = 999999999999999999;
printf("This is my_int: %I64d\n", my_int);

и я получаю это предупреждение компилятора:

warning: format ‘%I64d expects type int’, but argument 2 has type int64_t

Я пробовал с:

printf("This is my_int: %lld\n", my_int); // long long decimal

Но я получаю то же предупреждение. Я использую этот компилятор:

~/dev/c$ cc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5664~89/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5664)

Какой формат следует использовать для печати переменной my_int без предупреждения?

rtacconi
источник

Ответы:

420

Для int64_tтипа:

#include <inttypes.h>
int64_t t;
printf("%" PRId64 "\n", t);

для uint64_tтипа:

#include <inttypes.h>
uint64_t t;
printf("%" PRIu64 "\n", t);

Вы также можете использовать PRIx64для печати в шестнадцатеричном формате.

cppreference.com имеет полный список доступных макросов для всех типов, включая intptr_t( PRIxPTR). Есть отдельные макросы для scanf, вроде SCNd64.


Типичное определение PRIu16 было бы таким "hu", поэтому неявная конкатенация строк и констант происходит во время компиляции.

Чтобы ваш код был полностью переносимым, вы должны использовать PRId32и т. Д. Для печати int32_t, "%d"или аналогичные для печати int.

ouah
источник
18
Полный список форматирующих констант макроса: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
И, если вы используете C ++ в Linux, обязательно #define __STDC_FORMAT_MACROSперед включением inttypes.h.
csl
17
PRId64это макрос, который внутренне переводится в "lld". Итак, это так же хорошо, как писать. printf("%lld\n", t);См. Описание: qnx.com/developers/docs/6.5.0/…
Гаурав,
24
@Gaurav, это правда на некоторых платформах, но не на всех. Например, на моей машине amd64 Linux PRId64 определяется как ld. Портативность является причиной для макроса.
Итан Т
10
Я думаю, что с некоторыми дополнительными усилиями они могли бы сделать это еще более неприятным
Павел P
65

Путь С99

#include <inttypes.h>
int64_t my_int = 999999999999999999;
printf("%" PRId64 "\n", my_int);

Или вы могли бы бросить!

printf("%ld", (long)my_int);
printf("%lld", (long long)my_int); /* C89 didn't define `long long` */
printf("%f", (double)my_int);

Если вы застряли с реализацией C89 (в частности, с Visual Studio), вы можете использовать открытый исходный код <inttypes.h><stdint.h>): http://code.google.com/p/msinttypes/

PMG
источник
При использовании msinttypes из ссылки code.google.com мне нужно определить __STDC_FORMAT_MACROS. См. Stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
арискрис
Спасибо за внимание, @ariscris. Похоже, что макрос требуется только для C ++, хотя. Определения в связанном коде находятся внутри#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg
19

С C99 %jмодификатор длины также может использоваться с семейством функций printf для вывода значений типа int64_tи uint64_t:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    int64_t  a = 1LL << 63;
    uint64_t b = 1ULL << 63;

    printf("a=%jd (0x%jx)\n", a, a);
    printf("b=%ju (0x%jx)\n", b, b);

    return 0;
}

Компиляция этого кода с не gcc -Wall -pedantic -std=c99производит предупреждений, и программа выводит ожидаемый результат:

a=-9223372036854775808 (0x8000000000000000)
b=9223372036854775808 (0x8000000000000000)

Это соответствует printf(3)моей системе Linux (на странице man конкретно указано, что jона используется для обозначения преобразования в intmax_tили uintmax_t; в моем stdint.h оба int64_tи intmax_ttypedef'd точно таким же образом и аналогично для uint64_t). Я не уверен, что это идеально подходит для других систем.

pjhsea
источник
12
Если %jdprnts an intmax_t, правильный вызов будет printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). Там нет никакой гарантии , что int64_tи intmax_tтого же типа, и если они не являются, поведение не определено.
user4815162342
4
Вы можете переносимо использовать %jdдля печати int64_tзначения , если вы явно преобразовать их intmax_tперед передачей их printf: printf("a=%jd\n", (intmax_t)a). Это позволяет избежать (ИМХО) уродства <inttypes.h>макросов. Конечно, это предполагает, что ваша реализация поддерживает %jd, int64_tи intmax_tвсе они были добавлены C99.
Кит Томпсон
2
@KeithThompson "Уродство" слишком далеко заходит, приятель. Это абсолютно отвратительно. Это ужасно Это тошнотворно Это стыдно, что это такое. Или, по крайней мере, они должны быть смущены, много, что ввел это. Я никогда не видел этих макросов, но делаю то, что предлагает этот ответ и комментарии, включая ваши.
Pryftan
@Pryftan Я не совсем нахожу их такими же безобразными, как вы, и я совсем не уверен, как их можно определить менее уродливо без языковых изменений.
Кит Томпсон
@KeithThompson Хорошо, я благодарен, что вы хотя бы подчеркнули слово «вполне». Ну, на самом деле это не имеет значения. Я не понимаю, почему макросы должны быть там, хотя. Как вы говорите, вы можете переносить ... И т.д. Но потом я также обнаружил, что увеличение количества ключевых слов также вышло из-под контроля.
Pryftan
12

Исходя из встроенного мира, где даже uclibc не всегда доступен, и код вроде

uint64_t myval = 0xdeadfacedeadbeef; printf("%llx", myval);

печатает у вас дерьмо или не работает вообще - я всегда использую крошечный помощник, который позволяет мне правильно записать шестнадцатеричный uint64_t:

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

char* ullx(uint64_t val)
{
    static char buf[34] = { [0 ... 33] = 0 };
    char* out = &buf[33];
    uint64_t hval = val;
    unsigned int hbase = 16;

    do {
        *out = "0123456789abcdef"[hval % hbase];
        --out;
        hval /= hbase;
    } while(hval);

    *out-- = 'x', *out = '0';

    return out;
}
транквилизатор
источник
Если вы столкнулись с этой проблемой для встроенного приложения, то это то, что вы ищете. Это решение сработало для меня. Спасибо @ataraxic.
Logan859
8

В среде Windows используйте

%I64d

в Linux используйте

%lld
benlong
источник
18
%lldэто формат для long long int, который не обязательно совпадает с int64_t. <stdint.h>есть макрос для правильного формата для int64_t; посмотри ответ Оах .
Кит Томпсон
@KeithThompson Однако, поскольку long longон по крайней мере 64-разрядный, он printf("%lld", (long long)x);должен работать, за исключением, возможно, -0x8000000000000000, который не может быть представлен как, long longесли этот тип не использует дополнение до двух.
Паскаль Куок
@PascalCuoq: Да, он должен работать с приведением (и упомянутое вами исключение очень маловероятно, оно применимо только к системе, которая поддерживает дополнение до двух, но не использует его для long long).
Кит Томпсон,
-3

//VC6.0 (386 и лучше)

    __int64 my_qw_var = 0x1234567890abcdef;

    __int32 v_dw_h;
    __int32 v_dw_l;

    __asm
        {
            mov eax,[dword ptr my_qw_var + 4]   //dwh
            mov [dword ptr v_dw_h],eax

            mov eax,[dword ptr my_qw_var]   //dwl
            mov [dword ptr v_dw_l],eax

        }
        //Oops 0.8 format
    printf("val = 0x%0.8x%0.8x\n", (__int32)v_dw_h, (__int32)v_dw_l);

С уважением.

Даниэль Аг
источник