วิธีพิมพ์ int64_t ในซี


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 โดยไม่มีคำเตือน?


3
สำหรับ C ++ โปรดดูstackoverflow.com/questions/8132399/how-to-printf-uint64-t
Antonio

คำตอบ:


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


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ถูกกำหนดให้เป็น ความเบาเป็นเหตุผลสำหรับมาโคร
อีธาน T

10
ฉันคิดว่าด้วยความพยายามพิเศษบางอย่างที่พวกเขาสามารถทำให้น่ารังเกียจยิ่งกว่านี้อีก
Pavel P

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ด้วยวิธีเดียวกันและคล้ายกันuint64_t) ฉันไม่แน่ใจว่าจะพกพาไปยังระบบอื่นได้อย่างสมบูรณ์แบบหรือไม่


12
หาก%jdprnts intmax_t, printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a)ภาวนาที่ถูกต้องจะเป็น ไม่มีการรับประกันว่าไม่เป็นint64_tและintmax_tเป็นประเภทเดียวกันและถ้าพวกเขาไม่ได้มีพฤติกรรมจะไม่ได้กำหนด
user4815162342

4
คุณ portably สามารถใช้%jdในการพิมพ์int64_tค่าถ้าคุณอย่างชัดเจนแปลงให้intmax_tก่อนที่จะผ่านพวกเขาไปที่:printf printf("a=%jd\n", (intmax_t)a)วิธีนี้จะหลีกเลี่ยงความน่าเกลียด (IMHO) ของ<inttypes.h>มาโคร หลักสูตรนี้อนุมานว่าคุณสนับสนุนการดำเนินงาน%jd, int64_tและintmax_tทั้งหมดที่ถูกเพิ่มโดย C99
Keith Thompson

2
@ KeithThompson 'Uginess' กำลังนำมันไปไกลมากไกลเกินไป มันน่าเกลียดอย่างแน่นอน มันน่ากลัวมาก มันน่าขยะแขยง มันน่าอายคือสิ่งที่มันเป็น หรืออย่างน้อยพวกเขาควรจะอับอายมากที่แนะนำนี้ ฉันไม่เคยเห็นมาโครเหล่านี้ แต่ทำในสิ่งที่คำตอบนี้และความคิดเห็นของคุณรวมอยู่ด้วย - แนะนำ
Pryftan

@Pryftan ฉันไม่ค่อยพบว่าพวกเขาน่าเกลียดเท่าที่คุณทำ - และฉันก็ไม่แน่ใจว่าวิธีที่พวกเขาสามารถกำหนดในลักษณะที่น่าเกลียดน้อยกว่าโดยไม่ต้องเปลี่ยนภาษา
Keith Thompson

@ KeithThompson ดีฉันอย่างน้อยคุณก็ต้องขอบคุณความเครียดที่คำว่า 'ค่อนข้าง' จริงๆแล้วมันไม่สำคัญ ฉันไม่เห็นสาเหตุที่ต้องมีมาโคร อย่างที่คุณบอกว่าคุณสามารถพกพาได้ ... ฯลฯ แต่แล้วฉันก็พบว่าการเพิ่มจำนวนคำหลักก็เพิ่มขึ้นเช่นกัน
Pryftan

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

หากคุณกำลังประสบปัญหานี้สำหรับแอปพลิเคชันที่ฝังอยู่นี่คือสิ่งที่คุณกำลังมองหา วิธีนี้ใช้ได้ผลสำหรับฉัน ขอบคุณ @ataraxic
Logan859

8

ในสภาพแวดล้อมของ windows ให้ใช้

%I64d

ใน Linux ให้ใช้

%lld

18
%lldคือรูปแบบสำหรับlong long intซึ่งเป็นไม่int64_tจำเป็นต้องเหมือนกับ <stdint.h>มีมาโครสำหรับรูปแบบที่ถูกต้องสำหรับint64_t; ดูคำตอบของ ouah
Keith Thompson

@ KeithThompson อย่างไรก็ตามเนื่องจากlong longเป็นอย่างน้อย 64 บิตprintf("%lld", (long long)x);ควรทำงานยกเว้นบางทีสำหรับ -0x8000000000000000 ซึ่งไม่สามารถแทนได้เช่นเดียวกับlong longถ้าประเภทนั้นไม่ได้ใช้ส่วนประกอบสองอย่าง
ปาสกาล Cuoq

@PascalCuoq: ใช่มันควรจะทำงานร่วมกับนักแสดง (และข้อยกเว้นที่คุณพูดถึงไม่น่าจะเป็นไปได้มากที่ใช้เฉพาะกับระบบที่รองรับการเติมเต็มสองรายการ แต่ไม่ได้ใช้long long)
Keith Thompson

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

ความนับถือ.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.