Jak sformatować długi bez znaku długi int przy użyciu 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;
}

Wynik:

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

Zakładam, że ten nieoczekiwany wynik pochodzi z drukowania unsigned long long int. How do you printf()an unsigned long long int?

andrewrk
źródło
2
Właśnie skompilowałem twój kod (z% llu) z gcc i wynik był prawidłowy. Czy przekazujesz jakieś opcje do kompilatora?
Juan
2
Zauważ, że newlib Samsunga Bada wydaje się nie obsługiwać „% lld”: developer.bada.com/forum/…
RzR
Sugerowałbym użycie pliku stdint.h i wyraźne określenie liczby bitów w zmiennej. Nadal znajdujemy się w okresie przejściowym między architekturami 32- i 64-bitowymi, a „unsigned long long int” nie znaczy tego samego w obu.
BD w Rivenhill

Odpowiedzi:

483

Użyj długiego modyfikatora ll (el-el) z konwersją u (niepodpisaną). (Działa w systemie Windows, GNU).

printf("%llu", 285212672);
John Downey
źródło
11
Mówiąc ściślej, dotyczy GNU libc i nie działa w środowisku wykonawczym C. Microsoft.
Mark Baker,
168
To nie jest kwestia Linux / UNIX, modyfikator długości „ll” został dodany do standardu C w C99, jeśli nie działa w „Microsoft C”, to dlatego, że nie są one zgodne ze standardami.
Robert Gamble
12
Działa dla mnie w VS2008. Ponadto, o ile pamiętam, kompilator MS C (skonfigurowany do kompilacji prostej wersji C) powinien z założenia być zgodny z C90; C99 wprowadził pewne rzeczy, które nie wszystkim się podobały.
ス ー パ ー フ ァ ミ コ ン
6
Należy pamiętać, że jeśli przekazujesz wiele long longargumentów printfi używasz niewłaściwego formatu dla jednego z nich, powiedzmy %dzamiast %lld, to nawet argumenty wydrukowane po niewłaściwym mogą być całkowicie wyłączone (lub nawet spowodować printfawarię ). Zasadniczo zmienne argumenty są przekazywane do printf bez żadnych informacji o typie, więc jeśli łańcuch formatu jest niepoprawny, wynik jest nieprzewidywalny.
dmitrii
1
Słyszałem, że Herb Sutter powiedział w wywiadzie, że klienci Microsoftu nie pytają o C99, więc ich kompilator w czystym C został zamrożony w C90. Ma to zastosowanie, jeśli kompilujesz jako C. Jeśli kompilujesz jako C ++, jak zauważyli inni powyżej, wszystko powinno być w porządku.
ahcox,
90

Możesz spróbować użyć inttypes.h bibliotekę, która daje typów, takich jak int32_t, int64_t, uint64_titd. Następnie można korzystać z jego makr, takich jak:

uint64_t x;
uint32_t y;

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

To jest „gwarantowany”, aby nie dać ten sam problem, jak long, unsigned long longitp, ponieważ nie trzeba zgadywać, ile bitów są w każdym typie danych.

Nathan Fellman
źródło
gdzie te PRId64, PRId32zdefiniowane makra?
happy_marmoset,
4
@happy_marmoset: są zdefiniowani winttypes.h
Nathan Fellman,
4
Myślę, że trzeba PRIu64i PRIu32dla liczb całkowitych bez znaku.
Lasse Kliemann
1
Jest inttypes.hstandardem? Nie byłoby stdint.h?
MD XF,
2
Zauważ, że te typy dokładnej szerokości są opcjonalne , ponieważ istnieją architektury, które nie mają liczb całkowitych o tych dokładnych szerokościach. Obowiązkowe są tylko typy leastXi fastX(które mogą być szersze niż wskazane).
DevSolar
78

%d-> dla int

%u-> dla unsigned int

%ld-> dla long intlublong

%lu-> dla unsigned long intlub long unsigned intlubunsigned long

%lld-> dla long long intlublong long

%llu-> dla unsigned long long intlubunsigned long long

Shivam Chauhan
źródło
Czy istnieje specyfikator formatu, taki jak liczba cyfr do wyświetlenia, lewe lub prawe uzasadnienie dla% lld lub% llu?
Asam Padeh
40

W przypadku długiego (lub __int64) korzystania z MSVS należy użyć% I64d:

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

źródło
37

Wynika to z faktu, że% llu nie działa poprawnie w systemie Windows, a% d nie obsługuje 64-bitowych liczb całkowitych. Sugeruję użycie zamiast tego PRIu64, a przekonasz się, że jest również przenośny na Linuksa.

Spróbuj zamiast tego:

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

Wynik

My number is 8 bytes wide and its value is 285212672. A normal number is 5.
Paul Hargreaves
źródło
+1 za odniesienie do PRIu64, którego nigdy nie widziałem, ale nie wydaje się to przenośne dla 64-bitowego Linuksa (przynajmniej), ponieważ PRIu64 rozwija się do „lu” zamiast „llu”.
BD w Rivenhill
8
A dlaczego miałoby być tak źle? Długi to 64-bitowa wartość w 64-bitowym systemie Linux, jak w każdym innym systemie operacyjnym oprócz Windows.
Ringding
@BDatRivenhill Linux / Unix używa LP64, w której długość wynosi 64 bity
phuclv
1
jednak, aby uczynić go bardziej przenośnym, użyj int64_tzamiast niego, ponieważ mogą istnieć pewne implementacje z długim długim większym niż długim
phuclv
to powinno do góry! - jedna mała aktualizacja: błąd: nieprawidłowy przyrostek literału; C ++ 11 wymaga spacji między literałem a identyfikatorem [-Wreserved-user-zdefiniowanych-literal]
tofutim
14

W Linuksie jest, %lluaw Windowsie%I64u

Chociaż stwierdziłem, że nie działa w systemie Windows 2000, wydaje się, że jest tam błąd!

Adam Pierce
źródło
z Windows (lub przynajmniej z kompilatorem Microsoft dla Windows) jest także% I64d,% I32u i% I32d
JustJeff
1
Co to ma wspólnego z Windows 2000? Biblioteka C obsługuje bibliotekę printf.
CMircea,
1
Właśnie to zaobserwowałem. Napisałem aplikację, która wykorzystywała ten konstrukt i działała idealnie na WinXP, ale wyrzucała śmieci na Win2k. Może ma to coś wspólnego z wywołaniem systemowym, które biblioteka C wykonuje w jądrze, może ma to związek z Unicode, który wie. Pamiętam, że musiałem obejść to za pomocą _i64tot () lub czegoś podobnego.
Adam Pierce
7
Wygląda na to, że stwardnienie rozsiane ponownie korzysta ze swojej „swobody innowacji” ... ;-)
Dronz 12.12. O
Problem Win2k / Win9x prawdopodobnie wynika z tego, unsigned long longże typ danych jest stosunkowo nowy (w tym czasie ze standardem C99), ale kompilatory C (w tym MinGW / GCC) wykorzystują stary środowisko uruchomieniowe Microsoft C, które obsługuje tylko specyfikację C89. Mam dostęp tylko do naprawdę starych i dość aktualnych dokumentów Windows API. Trudno więc powiedzieć dokładnie, kiedy pojawiło się I64uwsparcie. Ale to brzmi jak epoka XP.
veganaiZe
8

Skompiluj go jako x64 za pomocą VS2005:

% llu działa dobrze.

Piaszczysty
źródło
3

Oprócz tego, co ludzie pisali lata temu:

  • możesz otrzymać ten błąd na gcc / mingw:

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

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

Wtedy twoja wersja mingw nie ma domyślnie c99. Dodaj tę flagę kompilatora: -std=c99.

Bernd Elkemann
źródło
3

Najwyraźniej nikt nie wymyślił rozwiązania wieloplatformowego * od ponad dziesięciu lat od [roku] 2008, więc dołączę moje 😛. Plz upvote. (Żartuję. Nie obchodzi mnie to.)

Rozwiązanie: lltoa()

Jak używać:

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

Przykład PO:

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

W przeciwieństwie do %lldciągu formatu wydruku, ten działa dla mnie pod 32-bitowym GCC w systemie Windows.

*) Cóż, prawie na wielu platformach. W MSVC najwyraźniej potrzebujesz _ui64toa()zamiast lltoa().

7vujy0f0hy
źródło
1
Nie mam lltoa.
Antti Haapala,
1

Niestandardowe rzeczy są zawsze dziwne :)

dla długiej, długiej części pod GNU to L, lllubq

a pod oknami uważam, że to lltylko

iskrzy
źródło
1

Klątwa:

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

Wynik:

64bit: FFFFFFFFFFFFFFFF
lama12345
źródło
Bardzo dobrze! zastanawiałem się, jak mogę to uzyskać w postaci szesnastkowej
0xAK,
Ale prawie wszystkie kompilatory C ++ i C dają ostrzeżenie: ostrzeżenie: użycie modyfikatora długości „ll” ze znakiem typu „p” [-Wformat =]
Seshadri R
2
ta całkowicie zepsuta odpowiedź ma podwójnie niezdefiniowane zachowanie i nawet nie zaczyna odpowiadać na pytanie .
Antti Haapala,
@AnttiHaapala Mówisz, że ta odpowiedź jest całkowicie łamana podwójnie niezdefiniowanym zachowaniem, czy możesz ją rozwinąć, czy mam ją po prostu usunąć? Czy może to dobry zły przykład?
lama12345,
0

Jednym ze sposobów jest skompilowanie go jako x64 z VS2008

Działa to tak, jak można się spodziewać:

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

W przypadku kodu 32-bitowego musimy użyć poprawnego specyfikatora formatu __int64% I64u. Tak się staje.

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

Ten kod działa zarówno dla 32-bitowego, jak i 64-bitowego kompilatora VS.

vzczc
źródło
Wypróbuj rzeczywistą liczbę 64-bitową zamiast „285212672” i nie sądzę, aby pierwszy przykład działał poprawnie, skompilowany z dowolnym celem.
dyasta