So drucken Sie einen int64_t-Typ in C.

298

Der C99-Standard hat ganzzahlige Typen mit einer Bytegröße wie int64_t. Ich verwende den folgenden Code:

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

und ich bekomme diese Compiler-Warnung:

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

Ich habe versucht mit:

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

Aber ich bekomme die gleiche Warnung. Ich benutze diesen Compiler:

~/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)

Welches Format soll ich verwenden, um die Variable my_int ohne Warnung zu drucken?

Rtacconi
quelle

Antworten:

420

Für int64_tTyp:

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

für uint64_tTyp:

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

Sie können auch PRIx64hexadezimal drucken.

cppreference.com bietet eine vollständige Liste der verfügbaren Makros für alle Typen, einschließlich intptr_t( PRIxPTR). Es gibt separate Makros für scanf, wie z SCNd64.


Eine typische Definition von PRIu16 wäre "hu", so dass zur Kompilierungszeit eine implizite Verkettung von Zeichenfolgenkonstanten auftritt .

Damit Ihr Code vollständig portierbar ist, müssen Sie PRId32usw. zum Drucken int32_tund "%d"ähnliches zum Drucken verwenden int.

ouah
quelle
18
Vollständige Liste der Formatierungsmakrokonstanten: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
Wenn Sie C ++ unter Linux verwenden, sollten Sie dies unbedingt tun, #define __STDC_FORMAT_MACROSbevor Sie es einschließen inttypes.h.
CSL
17
PRId64ist ein Makro, das intern übersetzt wird "lld". Es ist also so gut wie schreiben. printf("%lld\n", t);Siehe Beschreibung: qnx.com/developers/docs/6.5.0/…
Gaurav
24
@Gaurav, das stimmt auf einigen Plattformen, aber nicht auf allen. Auf meinem amd64 Linux-Computer ist PRId64 beispielsweise definiert als ld. Portabilität ist der Grund für das Makro.
Ethan T
10
Ich denke, mit etwas mehr Aufwand hätten sie es noch widerlicher machen können
Pavel P
65

Der C99 Weg ist

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

Oder du könntest besetzen!

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

Wenn Sie mit einer C89-Implementierung (insbesondere Visual Studio) nicht weiterkommen, können Sie möglicherweise Open Source <inttypes.h>(und <stdint.h>) verwenden: http://code.google.com/p/msinttypes/

pmg
quelle
Wenn ich msinttypes über den Link code.google.com verwende, muss ich __STDC_FORMAT_MACROS definieren. Siehe stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
Aristcris
Vielen Dank für das Heads-up, @ariscris. Es scheint jedoch, dass ein Makro nur für C ++ erforderlich ist. Die Definitionen in dem Code, #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg
19

Mit C99 kann der %jLängenmodifikator auch mit der Funktionsfamilie printf verwendet werden, um Werte vom Typ int64_tund zu drucken 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;
}

Das Kompilieren dieses Codes mit gcc -Wall -pedantic -std=c99erzeugt keine Warnungen und das Programm druckt die erwartete Ausgabe:

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

Dies ist printf(3)auf meinem Linux-System der Fall (die Manpage sagt ausdrücklich, dass dies jverwendet wird, um eine Konvertierung in ein intmax_toder anzuzeigen uintmax_t; in meiner stdint.h sind beide int64_tund intmax_twerden auf genau die gleiche Weise und ähnlich für typisiert uint64_t). Ich bin nicht sicher, ob dies perfekt auf andere Systeme portierbar ist.

pjhsea
quelle
12
Wenn %jdprnts an intmax_t, wäre der richtige Aufruf printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). Es gibt keine Garantie dafür, dass int64_tund intmax_tvom selben Typ sind, und wenn dies nicht der Fall ist, ist das Verhalten undefiniert.
user4815162342
4
Sie können Werte portabel %jddrucken int64_t, wenn Sie sie explizit in konvertieren, intmax_tbevor Sie sie an Folgendes übergeben printf: printf("a=%jd\n", (intmax_t)a). Dies vermeidet die (IMHO) Hässlichkeit der <inttypes.h>Makros. Natürlich setzt dies voraus , dass Ihre Implementierung unterstützt %jd, int64_tund intmax_t, die alle durch C99 hinzugefügt wurden.
Keith Thompson
2
@KeithThompson 'Hässlichkeit' bringt es viel, viel, viel zu freundlich, Kumpel. Es ist absolut schrecklich. Es ist schrecklich. Es ist übel. Es ist peinlich, was es ist. Oder zumindest sollten sie sich schämen, das Los, das dies eingeführt hat. Ich habe diese Makros noch nie gesehen, aber tun Sie, was diese Antwort und die Kommentare - Ihre eingeschlossen - nahelegen.
Pryftan
@Pryftan ich nicht recht finden sie ganz so hässlich , wie Sie tun - und ich bin nicht sicher , wie sie in einer weniger hässliche Art und Weise ohne Sprachänderungen definiert werden könnten.
Keith Thompson
@KeithThompson Nun, ich bin dankbar, dass Sie zumindest das Wort "ganz" betont haben. Nun, eigentlich spielt es keine Rolle. Ich verstehe nicht, warum die Makros da sein müssen. Wie Sie sagen, können Sie portabel ... usw. Aber dann finde ich auch, dass die Zunahme der Anzahl der Keywords auch außer Kontrolle geraten ist.
Pryftan
12

Ich komme aus der eingebetteten Welt, in der selbst uclibc nicht immer verfügbar ist, und Code wie

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

druckt du Mist oder funktioniert überhaupt nicht - ich benutze immer einen winzigen Helfer, der es mir ermöglicht, richtig zu entleeren 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;
}
ataraxisch
quelle
Wenn Sie mit diesem Problem für eine eingebettete Anwendung konfrontiert sind, ist dies genau das, wonach Sie suchen. Diese Lösung hat bei mir funktioniert. Danke @ataraxic.
Logan859
8

Verwenden Sie in einer Windows-Umgebung

%I64d

Verwenden Sie unter Linux

%lld
benlong
quelle
18
%lldist das Format für long long int, das nicht unbedingt das gleiche ist wie int64_t. <stdint.h>hat ein Makro für das richtige Format für int64_t; siehe ouahs Antwort .
Keith Thompson
@KeithThompson Da long longes jedoch mindestens 64-Bit ist, printf("%lld", (long long)x);sollte es funktionieren, außer vielleicht für -0x8000000000000000, was nicht als darstellbar sein könnte, long longwenn dieser Typ kein Zweierkomplement verwendet.
Pascal Cuoq
@PascalCuoq: Ja, es sollte mit der Besetzung funktionieren (und die von Ihnen erwähnte Ausnahme ist sehr unwahrscheinlich und gilt nur für ein System, das das Zweierkomplement unterstützt, es aber nicht verwendet long long).
Keith Thompson
-3

//VC6.0 (386 & besser)

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

Grüße.

Daniel Ag
quelle