Як надрукувати тип 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 без попередження?


Відповіді:


419

Для 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.


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/…
Gaurav

24
@Gaurav, це правда на деяких платформах, але не на всіх. Наприклад, на моїй машині Linux amd64 PRId64 визначено як ld. Переносність - причина макросу.
Етан Т

10
Я думаю, що з деякими додатковими зусиллями вони могли б зробити це ще більш неприємним
Павло П

65

Шлях C99 такий

#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/


Використовуючи msinttypes із посилання code.google.com, мені потрібно визначити __STDC_FORMAT_MACROS. Дивіться stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
ariscris

Дякую за голову вгору, @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_tвводятьсяdedef'd точно так само і аналогічно uint64_t). Я не впевнений, чи це чудово переноситься для інших систем.


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). Це дозволяє уникнути (IMHO) потворності <inttypes.h>макросів. Звичайно , це передбачає , що ваші опори реалізації %jd, int64_tі intmax_t, всі з яких були додані C99.
Кіт Томпсон

2
@KeithThompson "Потворність" ставить його далеко-далеко далеко надто доброзичливим товаришем. Це абсолютно огидно. Це примарно. Це нудота. Це соромно, що це таке. Або принаймні їх слід бентежити, доля, яка це ввела. Я ніколи не бачив цих макросів, але роби те, що підказує ця відповідь та коментарі - включаючи ваші.
Прифтан

@Pryftan Я не дуже вважаю їх такими некрасивими, як ти - і я зовсім не впевнений, як їх можна було б визначити менш потворним без зміни мови.
Кіт Томпсон

@KeithThompson Ну я вдячний, що ви принаймні наголосили на слові "цілком". Ну насправді це не має значення. Я не бачу, чому макроси повинні бути там. Як ви говорите, ви можете портативно ... І т. Д. Але потім я також вважаю, що збільшення кількості ключових слів також вийшло з рук.
Прифтан

12

Походить із вбудованого світу, де навіть uclibc не завжди доступний, і код подібний

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

друкує ви лайно або взагалі не працюєте - я завжди використовую крихітний помічник, який дозволяє мені скинути належним чином uint64_t hex:

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

Якщо ви зіткнулися з цим питанням для вбудованого додатку, то це саме те, що ви шукаєте. Це рішення спрацювало на мене. Thnx @ataraxic.
Logan859

8

У середовищі Windows використовуйте

%I64d

в Linux, використовувати

%lld

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

З повагою

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.