Niezależne od platformy specyfikatory formatu size_t w c?

86

Chcę wydrukować zmienną typu size_tw C, ale wygląda na to, że size_tjest aliasowana do różnych typów zmiennych na różnych architekturach. Na przykład na jednym komputerze (64-bitowym) poniższy kod nie generuje żadnych ostrzeżeń:

size_t size = 1;
printf("the size is %ld", size);

ale na moim innym komputerze (32-bitowym) powyższy kod generuje następujący komunikat ostrzegawczy:

ostrzeżenie: format „% ld” oczekuje typu „long int *”, ale argument 3 ma typ „size_t *”

Podejrzewam, że jest to spowodowane różnicą w rozmiarze wskaźnika, tak że na mojej 64-bitowej maszynie size_tjest aliasowany do a long int( "%ld"), podczas gdy na mojej 32-bitowej maszynie size_tjest aliasowany do innego typu.

Czy istnieje specyfikator formatu specjalnie dla size_t?

Ethan Heilman
źródło
Twoja wiadomość ostrzegawcza nie pasuje do kodu. Ostrzeżenie wspomina o wskaźnikach, Twój kod nie ma żadnych. Usunąłeś &gdzieś?
Jens
Wskaźniki? Nie, nie dostaję żadnych ostrzeżeń o wskaźnikach, w rzeczywistości w zależności od komputera, na którym uruchomię ten kod, czasami nie otrzymuję żadnych ostrzeżeń. Wypróbuj następujący kod testowy: #include <stdio.h> int main () {size_t size = 1; printf ("rozmiar to% ld", rozmiar); return 0; }
Ethan Heilman
1
@EthanHeilman On odnosząc się do faktu, że ostrzeżenia powiedzieć, warning: format '%ld' expects type 'long int *', but argument 3 has type 'size_t *'kiedy to prawdopodobnie powinno się mówić warning: format '%ld' expects type 'long int', but argument 3 has type 'size_t'. Czy scanf()zamiast tego korzystałeś z tych ostrzeżeń?
RastaJedi

Odpowiedzi:

123

Tak: użyj zmodyfikatora długości:

size_t size = sizeof(char);
printf("the size is %zu\n", size);  // decimal size_t ("u" for unsigned)
printf("the size is %zx\n", size);  // hex size_t

Inne dostępne modyfikatory długości to hh(za char), h(za short), l(za long), ll(za long long), j(za intmax_t), t(za ptrdiff_t) i L(za long double). Patrz §7.19.6.1 (7) standardu C99.

Adam Rosenfield
źródło
jaka jest różnica między zd i zu? Rozumiem, że zd jest dziesiętne, ale czy jest podpisane, jeśli tak, to jak podpisanie zd wpływa na rzeczy.
Ethan Heilman
1
To jest różnica między a size_ti an ssize_t; ten ostatni jest rzadko używany.
Adam Rosenfield
26
Racja, więc w tym przypadku powinieneś użyć %zu, ponieważ argument jest bez znaku.
kawiarnia
Inne dostępne opcje są wyjaśnione na stronie podręcznika printf: linux.die.net/man/3/printf
INS,
9
@detly: Nie, zmodyfikator długości nie jest częścią C89 / C90. Jeśli celujesz w kod zgodny z C89, najlepsze, co możesz zrobić, to rzutować unsigned longi użyć lzamiast tego modyfikatora długości, np printf("the size is %lu\n", (unsigned long)size);.; obsługa zarówno C89, jak i systemów z size_twiększymi niż longjest trudniejsza i wymagałaby użycia wielu makr preprocesora.
Adam Rosenfield,
45

Tak jest. Jest %zu(jak określono w ANSI C99).

size_t size = 1;
printf("the size is %zu", size);

Zauważ, że size_tjest bez znaku, więc %ldjest podwójnie błędny: zły modyfikator długości i niewłaściwy specyfikator konwersji formatu. Jeśli się zastanawiasz, %zdjest dla ssize_t(który jest podpisany).

maxschlepzig
źródło
1

MSDN mówi, że Visual Studio obsługuje prefiks „I” dla kodu przenośnego na platformach 32- i 64-bitowych.

size_t size = 10;
printf("size is %Iu", size);
Arkantos
źródło
6
jest specyficzny dla MS, co nie jest zgodne ze standardami, więc nie jest niezależny od platformy
phuclv
@phuclv Rzeczywiście. A jeśli naprawdę mówi - jak sugeruje odpowiedź - „przenośny”, to jest jeszcze gorszy niż kiedykolwiek wiedziałem o SM. Nie żeby mnie to zdziwiło ... Nie jestem osobą, która przegłosowała, ponieważ ktoś próbował odpowiedzieć na coś, ale ta odpowiedź jest po prostu błędna. Ach, myślę, że rozumiem ideę „przenośnego”. Trzeba powiedzieć, że działa zarówno w wersji 32-bitowej, jak i 64-bitowej. Ale oczywiście tak.
Pryftan