คุณจะทำการฟอร์แมท int long ที่ไม่ได้ลงนามโดยใช้ printf ได้อย่างไร?


379
#include <stdio.h>
int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %ul. A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

เอาท์พุท:

My number is 8 bytes wide and its value is 285212672l. A normal number is 0.

unsigned long long intผมถือว่าผลที่ไม่คาดคิดนี้มาจากการพิมพ์ คุณprintf()เป็นunsigned long long intอย่างไร


2
ฉันเพิ่งคอมไพล์โค้ดของคุณ (ด้วย% llu) ด้วย gcc และผลลัพธ์นั้นถูกต้อง คุณส่งตัวเลือกใด ๆ ไปยังคอมไพเลอร์หรือไม่?
Juan

2
โปรดทราบว่า newlib ของซัมซุงบาดาดูเหมือนจะไม่สนับสนุน "% lld": developer.bada.com/forum/ …
RzR


ฉันขอแนะนำให้ใช้การใช้ stdint.h และชัดเจนเกี่ยวกับจำนวนบิตในตัวแปรของคุณ เรายังอยู่ในช่วงของการเปลี่ยนแปลงระหว่างสถาปัตยกรรม 32 บิตและ 64 บิตและ "int long unsigned long long" ไม่ได้หมายถึงสิ่งเดียวกันทั้งคู่
BD ที่ Rivenhill

คำตอบ:


483

ใช้ตัวปรับเปลี่ยนแบบยาว (ll-el) ที่มีการแปลง u (ไม่ได้ลงนาม) (ทำงานใน windows, GNU)

printf("%llu", 285212672);

11
หรือเพื่อให้แม่นยำสำหรับ GNU libc และไม่ทำงานกับ C runtime ของ Microsoft
Mark Baker

168
นี่ไม่ใช่สิ่ง Linux / UNIX ตัวขยายความยาว "ll" ถูกเพิ่มใน Standard C ใน C99 ถ้ามันไม่ทำงานใน "Microsoft C" ก็เป็นเพราะพวกมันไม่ได้มาตรฐาน
Robert Gamble

12
ได้ผลสำหรับฉันใน VS2008 ยิ่งกว่านั้นเท่าที่ฉันจำ MS C Compiler (เมื่อตั้งค่าเพื่อคอมไพล์ C ตรง) ควรจะเป็นไปตาม C90 โดยการออกแบบ; C99 แนะนำบางสิ่งที่ทุกคนไม่ชอบ
スーパーファミコン

6
สิ่งหนึ่งที่ต้องจำไว้ที่นี่คือถ้าคุณผ่านการlong longขัดแย้งหลายครั้งprintfและใช้รูปแบบที่ไม่ถูกต้องสำหรับหนึ่งในพวกเขาพูด%dแทนจาก%lldนั้นแม้ข้อโต้แย้งที่พิมพ์หลังจากที่ไม่ถูกต้องอาจถูกปิดอย่างสมบูรณ์ (หรืออาจทำให้เกิดprintfความผิดพลาด ) โดยพื้นฐานแล้วอากิวเมนต์ของตัวแปรจะถูกส่งผ่านไปยัง printf โดยไม่มีข้อมูลชนิดใด ๆ ดังนั้นหากสตริงรูปแบบไม่ถูกต้องผลลัพธ์จะไม่สามารถคาดเดาได้
dmitrii

1
เฮิร์ตเฮิร์ตซัทเทอร์พูดในการให้สัมภาษณ์ว่าลูกค้าของ Microsoft ไม่ขอ C99 ดังนั้นคอมไพเลอร์ C บริสุทธิ์ของพวกเขาจึงถูกแช่แข็งที่ C90 สิ่งนี้มีผลถ้าคุณคอมไพล์เป็น C หากคุณคอมไพล์เป็น C ++ ดังที่คนอื่น ๆ ได้กล่าวไว้ข้างต้นคุณควรจะปรับ
ahcox

90

คุณอาจต้องการลองใช้ไลบรารี inttypes.h ที่ให้ประเภทเช่น int32_t, int64_tและuint64_tอื่น ๆ จากนั้นคุณสามารถใช้มาโครของมันเช่น:

uint64_t x;
uint32_t y;

printf("x: %"PRId64", y: %"PRId32"\n", x, y);

นี้คือ "รับประกัน" เพื่อไม่ให้ปัญหาเช่นเดียวกับlong, unsigned long longฯลฯ เนื่องจากคุณไม่ต้องคาดเดาว่าหลายบิตในแต่ละชนิดของข้อมูล


ที่เหล่านี้PRId64, PRId32แมโครกำหนด?
happy_marmoset

4
@happy_marmoset: มีการกำหนดไว้ในinttypes.h
Nathan Fellman

4
ฉันคิดว่าคุณต้องการPRIu64และPRIu32สำหรับจำนวนเต็มไม่ได้ลงนาม
Lasse Kliemann

1
เป็นinttypes.hมาตรฐานหรือไม่ มันจะstdint.hไม่เป็นอย่างนั้นหรือ
MD XF

2
โปรดทราบว่าประเภทความกว้างที่แน่นอนเหล่านี้เป็นตัวเลือกเนื่องจากมีสถาปัตยกรรมที่ไม่ได้มีประเภทจำนวนเต็มของความกว้างที่แน่นอนเหล่านั้น เฉพาะleastXและfastXประเภท (ซึ่งอาจกว้างกว่าที่ระบุจริง) เท่านั้นที่จำเป็น
DevSolar

78

%d-> สำหรับ int

%u-> สำหรับ unsigned int

%ld-> สำหรับlong intหรือlong

%lu-> สำหรับunsigned long intหรือlong unsigned intหรือunsigned long

%lld-> สำหรับlong long intหรือlong long

%llu-> สำหรับunsigned long long intหรือunsigned long long


มีตัวระบุรูปแบบเช่นจำนวนตัวเลขที่จะแสดงการจัดชิดซ้ายหรือขวาสำหรับ% lld หรือ% llu หรือไม่
Asam Padeh

40

เป็นเวลานาน (หรือ __int64) ที่ใช้ MSVS คุณควรใช้% I64d:

__int64 a;
time_t b;
...
fprintf(outFile,"%I64d,%I64d\n",a,b);    //I is capital i

37

นั่นเป็นเพราะ% llu ทำงานไม่ถูกต้องใน Windows และ% d ไม่สามารถจัดการกับจำนวนเต็ม 64 บิตได้ ฉันแนะนำให้ใช้ PRIu64 แทนและคุณจะพบว่ามันใช้งานได้กับ Linux

ลองใช้สิ่งนี้แทน:

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

int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    /* NOTE: PRIu64 is a preprocessor macro and thus should go outside the quoted string. */
    printf("My number is %d bytes wide and its value is %" PRIu64 ". A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

เอาท์พุต

My number is 8 bytes wide and its value is 285212672. A normal number is 5.

+1 สำหรับการอ้างอิงถึง PRIu64 ซึ่งฉันไม่เคยเห็นมาก่อน แต่ดูเหมือนว่าจะไม่สามารถพกพาไปที่ 64 บิต Linux (อย่างน้อย) เพราะ PRIu64 ขยายเป็น "lu" แทนที่จะเป็น "llu"
BD ที่ Rivenhill

8
และทำไมมันถึงไม่ดี? ความยาวคือค่า 64 บิตบน 64 บิต Linux เหมือนกับทุกระบบปฏิบัติการยกเว้น Windows
Ringding

@BDatRivenhill Linux / Unix ใช้ LP64 ซึ่งยาว 64 บิต
phuclv

1
อย่างไรก็ตามเพื่อให้สามารถพกพาได้มากกว่าให้ใช้int64_tแทนเพราะอาจมีการใช้งานบางอย่างที่มีขนาดใหญ่ยาวกว่ายาว
phuclv

นี่ควรขึ้นไปอยู่ข้างบน! - อัปเดตเล็กหนึ่งรายการ: ข้อผิดพลาด: ส่วนต่อท้ายที่ไม่ถูกต้องสำหรับตัวอักษร C ++ 11 ต้องการช่องว่างระหว่างตัวอักษรและตัวระบุ [-Weserved-user-defined-literal]
tofutim

14

ใน Linux มันเป็น%lluและใน Windows มันเป็น%I64u

แม้ว่าฉันจะพบว่ามันใช้งานไม่ได้ใน Windows 2000 แต่ดูเหมือนว่าจะมีข้อผิดพลาดอยู่ที่นั่น!


กับ windows, (หรืออย่างน้อยกับคอมไพเลอร์ microsoft C สำหรับ windows) นอกจากนี้ยังมี% I64d,% I32u และ% I32d
JustJeff

1
Windows 2000 ต้องทำอะไรบ้าง? ไลบรารี C คือไลบรารีที่จัดการ printf
CMircea

1
สิ่งที่ฉันสังเกตเห็น ฉันเขียนแอปที่ใช้โครงสร้างนี้และทำงานได้อย่างสมบูรณ์บน WinXP แต่ก็ทิ้งขยะใน Win2k บางทีมันอาจจะเป็นสิ่งที่ทำกับระบบที่เรียกว่าไลบรารี C ทำกับเคอร์เนลบางทีมันอาจจะเป็นสิ่งที่ทำกับ Unicode ที่รู้ ฉันจำได้ว่าต้องหลีกเลี่ยงโดยใช้ _i64tot () หรืออะไรทำนองนั้น
Adam Pierce

7
เสียงเช่น MS ออกกำลังกายของ "เสรีภาพในการสร้างสรรค์สิ่งใหม่ ๆ" อีกครั้ง ... ;-)
Dronz

ปัญหา Win2k / Win9x น่าจะเกิดจากunsigned long longประเภทข้อมูลที่ค่อนข้างใหม่ (ในเวลานั้นด้วยมาตรฐาน C99) แต่คอมไพเลอร์ C (รวมถึง MinGW / GCC) ใช้รันไทม์ Microsoft C เก่าซึ่งรองรับเฉพาะข้อมูลจำเพาะ C89 ฉันสามารถเข้าถึงเอกสาร Windows API ที่เก่าและสมเหตุสมผลที่สุดเท่านั้น ดังนั้นจึงเป็นการยากที่จะบอกได้อย่างแน่นอนว่าเมื่อใดที่I64uการสนับสนุนถูกทิ้งลงไป
veganaiZe


3

นอกจากสิ่งที่ผู้คนเขียนเมื่อหลายปีก่อน:

  • คุณอาจได้รับข้อผิดพลาดนี้ใน gcc / mingw:

main.c:30:3: warning: unknown conversion type character 'l' in format [-Wformat=]

printf("%llu\n", k);

ดังนั้นเวอร์ชัน mingw ของคุณจะไม่เป็น c99 เพิ่มธงคอมไพเลอร์นี้: -std=c99.


3

เห็นได้ชัดว่าไม่มีใครคิดวิธีแก้ปัญหาหลายแพลตฟอร์ม * มานานกว่าทศวรรษตั้งแต่ [ปี] ปี 2008 ดังนั้นฉันจะต่อท้าย mine โปรดโหวต (ล้อเล่นฉันไม่สนใจ)

สารละลาย: lltoa()

วิธีใช้:

#include <stdlib.h> /* lltoa() */
// ...
char dummy[255];
printf("Over 4 bytes: %s\n", lltoa(5555555555, dummy, 10));
printf("Another one: %s\n", lltoa(15555555555, dummy, 10));

ตัวอย่างของ OP:

#include <stdio.h>
#include <stdlib.h> /* lltoa() */

int main() {
    unsigned long long int num = 285212672; // fits in 29 bits
    char dummy[255];
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %s. "
        "A normal number is %d.\n", 
        sizeof(num), lltoa(num, dummy, 10), normalInt);
    return 0;
}

สิ่ง%lldนี้เหมาะกับฉันภายใต้ GCC 32 บิตบน Windows

*) ดีเกือบหลายแพลตฟอร์ม ใน MSVC คุณเห็นได้ชัดต้องแทน_ui64toa()lltoa()


1
lltoaฉันไม่ได้มี
Antti Haapala

1

สิ่งที่ไม่ได้มาตรฐานมีความแปลกอยู่เสมอ :)

สำหรับส่วนที่ยาวนานภายใต้ GNU มันL, llหรือq

และภายใต้หน้าต่างฉันเชื่อว่ามันเป็นllเพียง


1

hex:

printf("64bit: %llp", 0xffffffffffffffff);

เอาท์พุท:

64bit: FFFFFFFFFFFFFFFF

ดีมาก! ฉันสงสัยว่าฉันจะได้มันมาในรูปแบบ
เลข

แต่คอมไพเลอร์ C ++ และ C เกือบทั้งหมดให้คำเตือน: คำเตือน: การใช้ตัวปรับความยาว 'll' พร้อมกับตัวอักษรประเภท 'p' [-Wformat =]
Seshadri R

2
คำตอบนี้เสียอย่างเต็มที่มีพฤติกรรมทวีคูณไม่ได้กำหนดและไม่ได้เริ่มต้นที่จะตอบคำถาม
Antti Haapala

@AnttiHaapala คุณพูดว่าคำตอบนี้ถูกทำลายอย่างสิ้นเชิงกับพฤติกรรมที่ไม่ได้กำหนดสองเท่าคุณสามารถอธิบายอย่างละเอียดได้หรือว่าฉันจะลบมันได้หรือไม่ หรือเก็บไว้เป็นตัวอย่างที่ดี
lama12345

0

วิธีหนึ่งคือการคอมไพล์มันเป็น x64 กับ VS2008

สิ่งนี้จะทำงานตามที่คุณคาดหวัง:

int normalInt = 5; 
unsigned long long int num=285212672;
printf(
    "My number is %d bytes wide and its value is %ul. 
    A normal number is %d \n", 
    sizeof(num), 
    num, 
    normalInt);

สำหรับรหัส 32 บิตเราต้องใช้ตัวระบุรูปแบบ __int64 ที่ถูกต้อง% I64u ดังนั้นมันจึงกลายเป็น

int normalInt = 5; 
unsigned __int64 num=285212672;
printf(
    "My number is %d bytes wide and its value is %I64u. 
    A normal number is %d", 
    sizeof(num),
    num, normalInt);

รหัสนี้ใช้ได้กับคอมไพเลอร์ VS 32 และ 64 บิต


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