Powody używania (lub nie) stdint

Wiem już, że stdint jest używany, gdy potrzebujesz konkretnych rozmiarów zmiennych do przenoszenia między platformami, naprawdę nie mam takiego problemu na razie, ale jakie są wady i zalety korzystania z niego oprócz de już pokazany fakt powyżej?

Szukając go na stronach stackoverflow i innych, znalazłem 2 Linki, które traktują o temacie:

  • 1 - ten mówi o przenośności stdint.

  • 2 - ten jest bardziej szczegółowy o uint8_t.

Tezy dwa linki są świetne szczególnie o dowiedzieć się więcej o głównym powodem tego nagłówka, który jest przenośność, ale dla mnie, co najbardziej lubię w tym, że myślę, że uint8_t jest czystsze niż unsigned char (do przechowywania wartości kanału RBG na przykład), int32_t wygląda bardziej sensowne niż po prostu int, itp.

Więc, moje pytanie brzmi, dokładnie, jakie są wady, a zwłaszcza plusy korzystania z stdint oprócz przenośności, i czy powinienem używać go tylko w niektórych wyszczególnia części mojego kodu, czy wszędzie? jeśli wszędzie, jak mogę z nim korzystać z funkcji użytkownika, takich jak atoi, strtok itp.?

Dzięki!

Author: Community, 2012-03-23

4 answers

Plusy

Użycie dobrze zdefiniowanych typów sprawia, że kod jest znacznie łatwiejszy i bezpieczniejszy w przenoszeniu, ponieważ nie będzie niespodzianek, gdy na przykład jedna maszyna zinterpretuje int jako 16-bitową, a druga jako 32-bitową. Ze stdint.H, to, co piszesz, jest tym, co dostajesz.

Używanie int etc utrudnia również wykrywanie niebezpiecznych promocji typu.

Kolejną zaletą jest to, że używając int8_t zamiast char, wiesz, że zawsze otrzymujesz podpisaną zmienną 8-bitową. char może być podpisany lub niepodpisany, jest zachowanie zdefiniowane przez implementację i różni się między kompilatorami. Dlatego domyślne char jest po prostu niebezpieczne w kodzie, który powinien być przenośny.

Jeśli chcesz dać kompilatorowi podpowiedź, że zmienna powinna być zoptymalizowana, możesz użyć uint_fastx_t, która mówi kompilatorowi, aby użył najszybszego możliwego typu integer, co najmniej tak dużego jak 'x'. W większości przypadków nie ma to znaczenia, kompilator jest wystarczająco inteligentny, aby optymalizować rozmiary typów bez względu na to, co wpisałeś. Pomiędzy punktami sekwencji kompilator może domyślnie zmienić typ na inny niż podany, o ile nie ma to wpływu na wynik.

Cons

Brak.


Odniesienie: MISRA-C: 2004 przepis 6.3." typedefs , które wskazują rozmiar i oznaczenie, stosuje się zamiast podstawowych typów".

EDIT: usunięto niepoprawny przykład.

 61
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-21 14:09:28

Jedynym powodem, aby używać uint8_t zamiast unsigned char (poza preferencjami estetycznymi) jest to, że chcesz udokumentować, że twój program wymaga char Dokładnie 8 bitów. uint8_t Istnieje wtedy i tylko wtedy, gdy CHAR_BIT==8, zgodnie z wymaganiami normy C.

Reszta typów intX_t i uintX_t jest przydatna w następujących sytuacjach:

  • Odczyt / Zapis dysku / sieci (ale wtedy musisz również użyć funkcji konwersji endian)
  • gdy chcesz unsigned wraparound zachowanie przy dokładnym odcięciu (ale można to zrobić bardziej przenośnie za pomocą operatora &).
  • gdy kontrolujesz dokładny układ struktury, ponieważ musisz upewnić się, że nie istnieje wypełnienie (np. dla memcmp lub celów hashujących).

Z drugiej strony uint_least8_t, itd. typy są przydatne wszędzie tam, gdzie chcesz uniknąć używania zbyt dużych lub powolnych typów, ale musisz mieć pewność, że możesz przechowywać wartości o określonej wielkości. Na przykład, gdy long long ma co najmniej 64 bity, to na niektórych maszynach może być 128-bitowy, a używanie go, gdy potrzebujesz tylko typu, który może przechowywać numery 64-bitowe, byłoby bardzo marnotrawne na takich maszynach. int_least64_t rozwiązuje problem.

Unikałbym całkowicie używania typów [u]int_fastX_t, ponieważ czasami zmieniały się na danej maszynie (łamiąc ABI) i ponieważ definicje są zwykle błędne. Na przykład, na x86_64, 64-bitowy Typ integer jest uważany za "szybki" Dla wartości 16-, 32-i 64-bitowych, ale podczas dodawania, odejmowanie i mnożenie to dokładnie ta sama prędkość niezależnie od tego, czy używasz wartości 32-bitowych, czy 64-bitowych, dzielenie jest prawie na pewno wolniejsze przy większych niż konieczne typach, a nawet jeśli były one taką samą prędkością, używasz dwukrotnie większej pamięci bez żadnych korzyści.

Na koniec, zauważ, że argumenty, które pojawiły się w niektórych odpowiedziach na temat nieefektywności użycia int32_t dla licznika, gdy nie jest to natywna wielkość całkowita, są technicznie w większości poprawne, ale nie ma znaczenia poprawność kodu. Chyba, że jesteś zliczając niewielką liczbę rzeczy, na których maksymalna liczba jest pod twoją kontrolą, lub jakąś zewnętrzną (nie znajdującą się w pamięci programu) rzecz, w której liczba może być astronomiczna, prawidłowym typem dla liczenia jest prawie zawsze size_t. Dlatego wszystkie standardowe funkcje C używają size_t do zliczania. Nie myśl o używaniu niczego innego, chyba że masz bardzo dobry powód.

 16
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-23 12:13:22

Cons

Główny powód, dla którego język C nie określa wielkości int LUB long, itd. jest dla wydajności obliczeniowej. Każda architektura ma naturalny, najbardziej wydajny rozmiar, a projektanci specjalnie upoważnili i zamierzali implementatora kompilatora do korzystania z naturalnych danych natywnych dla szybkości i wydajności rozmiaru kodu.

W minionych latach komunikacja z innymi maszynami nie była głównym problemem-większość programów była lokalna dla maszyny-więc przewidywalność rozmiar każdego typu danych był niewielki.

Naleganie, aby konkretna Architektura używała określonego rozmiaru int do liczenia Z jest naprawdę złym pomysłem , chociaż wydaje się, że ułatwia to inne rzeczy.

W pewnym sensie, dzięki XML i jego braciom, Rozmiar typu danych ponownie nie jest już problemem. Przesyłanie specyficznych dla maszyny struktur binarnych z maszyny do maszyny jest znowu wyjątkiem, a nie regułą.

 7
Author: wallyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-23 06:24:31

Używam typów stdint tylko z jednego powodu, gdy dane, które przechowuję w pamięci, trafiają na dysk/sieć/deskryptor w postaci binarnej. Musisz tylko walczyć z problemem little-endian/big-endian, ale jest to stosunkowo łatwe do przezwyciężenia.

Oczywistym powodem nie do używania stdint jest to, że kod jest niezależny od rozmiaru, w matematyce wszystko, co działa nad racjonalnymi liczbami całkowitymi. Wygenerowałoby to brzydkie duplikaty kodu, gdybyś podał uint*_t wersję, powiedzmy, qsort() dla każde rozszerzenie *.

Używam w tym przypadku własnych typów, wywodzących się z size_t, Gdy jestem leniwy, lub największej obsługiwanej niepodpisanej liczby całkowitej na platformie, gdy nie jestem.

Edit, bo natknąłem się na ten problem wcześniej:
Myślę, że warto zauważyć, że przynajmniejuint8_t, uint32_t i uint64_t są zepsute w Solarisie 2.5.1. Tak więc dla maksymalnej przenośności nadal sugeruję unikanie stdint.h (przynajmniej przez najbliższe kilka lat).

 6
Author: hroptatyr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-05 09:10:10