Mam kod w C ++, który wyświetla size_t
:
size_t a;
printf("%lu", a);
Chciałbym, aby kompilacja przebiegła bez ostrzeżeń na architekturach 32- i 64-bitowych.
Gdyby to był C99, mógłbym użyć printf("%z", a);
. Ale AFAICT %z
nie istnieje w żadnym standardowym dialekcie C ++. Więc zamiast tego muszę zrobić
printf("%lu", (unsigned long) a);
co jest naprawdę brzydkie.
Jeśli nie ma możliwości drukowania size_t
s wbudowanych w język, zastanawiam się, czy można napisać opakowanie printf lub coś takiego, które wstawi odpowiednie rzutowania na size_t
s, aby wyeliminować fałszywe ostrzeżenia kompilatora, jednocześnie zachowując dobre.
Jakieś pomysły?
Edytuj Aby wyjaśnić, dlaczego używam printf: Mam stosunkowo dużą bazę kodu, którą czyszczę. Używa opakowań printf do wykonywania takich czynności, jak „napisz ostrzeżenie, zaloguj się do pliku i prawdopodobnie zamknie kod z błędem”. Być może uda mi się zebrać wystarczającą liczbę C ++ - foo, aby to zrobić za pomocą opakowania cout, ale wolałbym nie zmieniać każdego wywołania warn () w programie tylko po to, aby pozbyć się niektórych ostrzeżeń kompilatora.
"%l"
? Czy to nie zawsze będzie odpowiedni rozmiar? A może przenośność ma znaczenie?Odpowiedzi:
Większość kompilatorów ma własne specyfikatory
size_t
iptrdiff_t
argumenty, na przykład Visual C ++ używa odpowiednio% Iu i% Id, myślę, że gcc pozwoli ci użyć% zu i% zd.Możesz stworzyć makro:
Stosowanie:
źródło
%z
jest obsługiwana, czy nie, zależy od środowiska wykonawczego, a nie od kompilatora. Używanie__GNUC__
jest więc pewnym problemem, jeśli zmieszasz GCC / mingw z msvcrt (i bez użycia rozszerzonego printf mingw).Specyfikator
printf
formatu%zu
będzie działał dobrze w systemach C ++; nie ma potrzeby, aby było to bardziej skomplikowane.źródło
C ++ 11
C ++ 11 importuje C99, więc
std::printf
powinien obsługiwać specyfikator%zu
formatu C99 .C ++ 98
Na większości platform
size_t
iuintptr_t
są równoważne, w takim przypadku możesz użyćPRIuPTR
makra zdefiniowanego w<cinttypes>
:Jeśli naprawdę chcesz być bezpieczny, przesyłaj
uintmax_t
i używajPRIuMAX
:źródło
W systemie Windows i implementacji programu Visual Studio printf
pracuje dla mnie. zobacz msdn
źródło
VS 2008
też. Należy także pamiętać, że można użyć%Id
,%Ix
i%IX
zbyt.Skoro używasz C ++, dlaczego nie skorzystać z IOStreams? Powinno to skompilować się bez ostrzeżeń i działać poprawnie ze świadomością typu, o ile nie używasz martwej dla mózgu implementacji C ++, która nie definiuje
operator <<
forsize_t
.Kiedy trzeba wykonać rzeczywiste dane wyjściowe
printf()
, nadal można je połączyć z IOStreams, aby uzyskać zachowanie bezpieczne dla typów:Nie jest to super wydajne, ale powyższy przypadek dotyczy operacji we / wy pliku, więc to jest wąskie gardło, a nie ten kod formatujący ciąg.
źródło
std::stringstream
zamiast strumieni we / wy.printf("x=%i, y=%i;\n", x, y);
vscout << "x=" << x << ", y=" << y << ";" << std::endl;
.oto możliwe rozwiązanie, ale nie całkiem ładne ...
źródło
Biblioteki FMT zapewnia szybki przenośny (i bezpieczne) wdrażanie
printf
tymz
modyfikator dlasize_t
:Oprócz tego obsługuje składnię ciągów formatu podobną do Pythona i przechwytuje informacje o typie, dzięki czemu nie musisz podawać ich ręcznie:
Został przetestowany z głównymi kompilatorami i zapewnia spójne wyniki na różnych platformach.
Zastrzeżenie : jestem autorem tej biblioteki.
źródło
Efektywny typ będący podstawą size_t zależy od implementacji . C Standard definiuje go jako typ zwracany przez operator sizeof; Oprócz tego, że jest bez znaku i jest rodzajem typu całkowitego, size_t może być prawie wszystkim, którego rozmiar może pomieścić największą wartość, której oczekuje się od sizeof ().
W związku z tym ciąg formatu, który ma być używany dla parametru size_t, może się różnić w zależności od serwera. Powinien zawsze mieć „u”, ale może to być l lub d, a może coś innego ...
Sztuczka może polegać na rzutowaniu go na największy typ całkowity na maszynie, zapewniając brak strat w konwersji, a następnie użycie ciągu formatu związanego z tym znanym typem.
źródło
size_t
s na największy typ całkowity na maszynie i używając ciągu formatu związanego z tym typem. Moje pytanie brzmi: czy istnieje sposób, w jaki mogę to zrobić, zachowując czysty kod (ostrzeżenia tylko o prawidłowych błędach w ciągu formatu printf, bez brzydkich rzutów itp.)? Mógłbym napisać opakowanie, które zmienia ciąg formatu, ale wtedy GCC nie byłby w stanie dać mi ostrzeżeń, kiedy legalnie zepsułem swój ciąg formatu.Później w kodzie:
my::printf("test ", 1, '\t', 2.0);
źródło