Jak wydrukować typy takie jak off_t i size_t?

148

Próbuję drukować typy takie jak off_ti size_t. Jaki jest prawidłowy symbol zastępczy dla printf() tego, że jest przenośny ?

A może jest zupełnie inny sposób drukowania tych zmiennych?

Georg Schölly
źródło
2
@devin: Wierzę Znalazłem tego typu podczas używania fopen, fseekitp na Mac OS X. off_tsłuży do przesunięcia.
Georg Schölly

Odpowiedzi:

112

Możesz użyć zdla size_t i tdla ptrdiff_t jak w

printf("%zu %td", size, ptrdiff);

Ale moja strona podręcznika mówi, że jakaś starsza biblioteka używała innego znaku niż zi zniechęca do jego używania. Niemniej jednak jest znormalizowany (według standardu C99). Dla tych intmax_ti int8_tod stdint.hi tak dalej, są makra można użyć, jak inna odpowiedź powiedział:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Są one wymienione na stronie podręcznika inttypes.h.

Osobiście chciałbym po prostu przypisać wartości unsigned longlub longpolubić inne zalecenia. Jeśli korzystasz z C99, następnie można (a nawet powinien, oczywiście) oddanych do unsigned long longlub long longi użyj %llulub %lldformatów odpowiednio.

Johannes Schaub - litb
źródło
2
off_t to w rzeczywistości długi znak ze znakiem w moim systemie.
Georg Schölly
2
Myślę, że strona podręcznika odradza używanie Z (wielkich liter), które było używane przez libc5. To nie wydaje się zniechęcać z (małe litery).
Draemon
12
Używanie %zdz a size_tjest niezdefiniowanym zachowaniem z powodu niezgodności podpisów (C99 7.19.6.1 # 9). To musi być %zu.
Jens
7
Jak więc wydrukować off_t?
JohnyTex,
3
@Jens Nie rozumiem, jak za %zdpomocą a size_tuzyskuje się niezdefiniowane zachowanie z tego akapitu lub innego. W rzeczywistości, definicja %zw 7 wyraźnie zezwala %dsię size_ti podpisał odpowiedni typ i §6.2.5 # 9 wyraźnie pozwala na stosowanie wartości niepodpisanych typów gdzie spodziewane jest odpowiedni typ podpisana, dopóki wartość jest prawidłową wartością dodatnią podpisanego typu.
Chortos-2
108

Aby wydrukować off_t:

printf("%jd\n", (intmax_t)x);

Aby wydrukować size_t:

printf("%zu\n", x);

Aby wydrukować ssize_t:

printf("%zd\n", x);

Zobacz 7.19.6.1/7 w standardzie C99 lub wygodniejszą dokumentację POSIX dotyczącą kodów formatowania:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html

Jeśli twoja implementacja nie obsługuje tych kodów formatujących (na przykład ponieważ jesteś na C89), masz mały problem, ponieważ AFAIK nie ma typów całkowitych w C89, które mają kody formatujące i gwarantują, że są tak duże jak te typy. Musisz więc zrobić coś specyficznego dla implementacji.

Na przykład, jeśli Twój kompilator ma long longi obsługuje standardową bibliotekę %lld, możesz śmiało oczekiwać, że będzie to służyć zamiast intmax_t. Ale jeśli tak się nie stanie, będziesz musiał wrócić do long, co w przypadku niektórych innych implementacji nie powiedzie się, ponieważ jest za małe.

Steve Jessop
źródło
3
To jest zdecydowanie lepsza odpowiedź, zapomniałbym o używaniu% zu dla unsigned size_t. Przesyłanie do intmax_t to świetne rozwiązanie na wszystko, co off_t jest na dowolnej platformie.
Peter Cordes
2
POSIX nie gwarantuje, że ssize_tma taki sam rozmiar jak size_t, więc prawdziwie przenośny kod powinien go konwertować intmax_ti drukować z %jdtakim samym off_t.
nwellnhof
off_t może mieć maksymalnie długi rozmiar i może być zmienna w zależności od definicji ... Program Visual Studio ostrzega również z tym „ostrzeżeniem C4477:„ _snprintf_s ”: ciąg formatu„% jd ”wymaga argumentu typu„ __int64 ”, ale argument wariadyczny 1 ma typ 'off_t' "... Naprawdę przenośnym sposobem jest printf ("% lld \ n ", (long long) x);
ericcurtin
5

W przypadku firmy Microsoft odpowiedź jest inna. VS2013 jest w dużej mierze zgodny z C99, ale „[t] he hh, j, z i t prefiksy długości nie są obsługiwane”. Dla size_t "to znaczy unsigned __int32 na platformach 32-bitowych, unsigned __int64 na platformach 64-bitowych" użyj przedrostka I (wielkie oko) ze specyfikatorem typu o, u, x lub X. Zobacz specyfikację rozmiaru VS2013

Jeśli chodzi o off_t, jest zdefiniowany jako długi w VC \ include \ sys \ types.h.

NoBrassRing
źródło
Zauważ, że jeśli off_tzawsze jest longto 32-bitowe (nawet 64-bitowy system Windows używa 32-bitowego long).
sourcejedi
3

Której wersji C używasz?

W C90 standardową praktyką jest rzutowanie odpowiednio do długości ze znakiem lub bez znaku i odpowiednie drukowanie. Widziałem% z dla size_t, ale Harbison i Steele nie wspominają o tym w printf (), aw każdym razie to nie pomoże ci z ptrdiff_t lub czymkolwiek.

W C99 różne typy _t mają własne makra printf, więc coś w rodzaju "Size is " FOO " bytes." nie znam szczegółów, ale jest to część dość dużego pliku dołączanego formatu liczbowego.

David Thornley
źródło
3

Będziesz chciał użyć makr formatujących z inttypes.h.

Zobacz to pytanie: Ciąg formatu międzyplatformowego dla zmiennych typu size_t?

Michael Burr
źródło
Zakładając, że off_t jest znakiem int o rozmiarze wskaźnika (nie wiem, jaka jest dokładna definicja), jak ptrdiff_t, użyjesz PRIdPTR lub PRIiPTR.
Michael Burr
11
off_tTyp jest większy niż wskaźnik w dowolnym systemie 32-bitowym, który obsługuje duże pliki (co jest większość 32-bitowe systemy te dni).
Dietrich Epp
1
@DietrichEpp: Właściwie jest gorzej; wiele systemów 32-bitowych ma zarówno off_t, jak i off64_t, aw zależności od funkcji makra off_t może faktycznie oznaczać off64_t.
SamB
1

Patrząc man 3 printfna Linuksa, OS X i OpenBSD, wszystkie pokazują wsparcie %zdla size_ti %tdla ptrdiff_t(dla C99), ale żadne z nich nie wspomina off_t. Sugestie w środowisku naturalnym zazwyczaj oferują %ukonwersję off_t, która jest „wystarczająco poprawna”, o ile wiem (oba unsigned inti off_tróżnią się identycznie między systemami 64-bitowymi i 32-bitowymi).

dwc
źródło
1
Mój system (OS X) jest 32-bitowy unsigned inti 64-bitowy off_t. Więc obsada spowodowałaby utratę danych.
Dietrich Epp
-3

Widziałem ten post co najmniej dwa razy, ponieważ zaakceptowaną odpowiedź trudno mi zapamiętać (rzadko używam zlub jflag i wydaje się, że nie są niezależne od platformy ).

Norma nie mówi wyraźnie dokładna długość danych size_t, więc proponuję najpierw należy sprawdzić długość size_tod platformy, a następnie wybrać jedną z nich:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

I sugeruję używanie stdinttypów zamiast surowych typów danych w celu zachowania spójności.

elinx
źródło
1
W przypadku C99 i C11 norma wyraźnie określa, %zuktórych można użyć do wydrukowania size_twartości. Trzeba na pewno nie uciekać się do korzystania z uint32_t/ uint64_tformatu specyfikatora aby wydrukować size_t, ponieważ nie ma gwarancji, że te typy są kompatybilne.
autystyczny
-4

Jak sobie przypominam, jedynym przenośnym sposobem na zrobienie tego jest rzutowanie wyniku na „unsigned long int” i użycie %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
James Curran
źródło
1
Powinien mieć wartość „% lu”, ponieważ modyfikator długości powinien znajdować się przed konwersją.
dwc
1
Na przykład off_t to long long ze znakiem.
Georg Schölly
@ GeorgSchölly - Wtedy trafiłeś na zagadkę, ponieważ long longnie istnieje w standardzie C ++, a zatem jest z natury nieprzenośny.
James Curran
-9

użyj „% zo” dla off_t. (ósemkowo) lub „% zu” dla liczby dziesiętnej.

Shankar
źródło
Dlaczego chcesz, aby przesunięcie pliku było ósemkowe?
poolie