2013-05-03 17 views
6

W standardzie C99 sekcja 7.18.4.1 "Makra dla stałych całkowitych o minimalnej szerokości", niektóre makra zdefiniowane jako [U]INT[N]_C(x) do rzutowania stałych liczb całkowitych do najmniejszych typów danych, gdzie N = 8, 16, 32, 64. Dlaczego te makra są zdefiniowane, ponieważ mogę zamiast tego używać modyfikatorów L, UL, LL lub ULL? Na przykład, gdy chcę użyć co najmniej 32 bity bez znaku stałej liczby całkowitej, mogę po prostu napisać 42UL zamiast UINT32_C(42). Ponieważ długi typ danych ma co najmniej 32 bity szerokości, jest również przenośny.Jaki jest cel "Makr dla stałych całkowitych o minimalnej szerokości"

Jaki jest cel tych makr?

+0

Myślę, że są tak, że nie musisz się martwić o takie rzeczy, jak duże "int" lub "długie" podczas tworzenia własnych typów stałych liczb całkowitych. –

Odpowiedz

7

należałoby je w miejscach, w których chcesz się upewnić, że nie staną się one zbyt szeroko

#define myConstant UINT32_C(42) 

a później

printf("%" PRId32 " is %s\n", (hasproperty ? toto : myConstant), "rich"); 

tutaj, jeśli stała się będzie UL wyrażenie może być ulong, a funkcja variadic może umieścić na stosie wartość 64-bitową, która zostałaby błędnie zinterpretowana przez printf.

+0

Czy sugerujesz, że długi może być 64-bitowy na niektórych 32-bitowych platformach? Dlatego byłby problematyczny w niektórych funkcjach, takich jak printf. Jeśli tak, miałoby to również wpływ na wydajność, ponieważ manipulowanie liczbą całkowitą 64-bitową występuje, gdy wystarczą 32-bitowe. – obareey

+1

Tak, to zależy od projektantów platformy, którzy podejmą decyzję.I nie przeceniaj różnicy wydajności dla operacji na liczbach całkowitych o różnej szerokości, na nowoczesnych maszynach nie ma żadnej dla samej arytmetyki. Jedyną różnicą może być to, że wykonujesz wiele takich operacji w pętli, a dostęp do pamięci byłby wąskim gardłem. Wręcz przeciwnie, nowoczesne procesory AVX wykonują operacje 256-bitowe tak szybko, jak operacje 32-bitowe, więc generalnie niewłaściwy jest wybór typów o określonej szerokości. Użyj 'size_t',' ptrdiff_t' i podobnych rzeczy, które pasują do semantyki tego, co robisz. –

+0

Czy istnieją 16-bitowe kompilatory, w których statyczne 'const uint32_t var = 0xFFFF0000;' może spowodować var ​​= 0x0000? Co mówią specyfikacje C99 i C89 na temat wielkości stałej? – Samuel

3

je używać najmniejsza typu całkowitą o szerokości co najmniej N, tak UINT32_C(42) odpowiada tylko 42UL w systemach, int jest mniejszy niż 32 bitów. W systemach, w których int ma 32 bity lub więcej, UINT32_C(42) jest równoważne 42U. Można nawet wyobrazić sobie system, w którym short ma szerokość 32 bitów, w którym to przypadku UINT32_C(42) byłby równoważny (unsigned short)42.

EDYCJA: @obareey Wydaje się, że większość, jeśli nie wszystkie, implementacje standardowej biblioteki nie są zgodne z tą częścią normy, być może dlatego, że jest to niemożliwe. [glibc bug 2841] [glibc commit b7398be5]

+0

Ale na tych platformach nie ma znaczenia, czy 32-bitowe jest krótkie, ponieważ byłaby to najszybsza liczba całkowita z co najmniej 32-bitami, lub tak myślałem. Teraz jestem zdezorientowany. Ponieważ zapisuje "Makro UINTN_C (wartość) musi rozwinąć się do stałego wyrażenia liczb całkowitych odpowiadającego typowi uint_leastN_t" w standardzie, ale 32-bitowy kompilator ARM definiuje "#define UINT8_C (x) (x ## u)" i " #define UINT16_C (x) (x ## u) "bez rzutowania. – obareey

+0

Najmniejszy, nie najszybszy. – Oktalist

+0

Zastanawiam się, jak często którekolwiek z tych makr są używane, aby uczynić kod bardziej przenośnym? Semantyka rzeczy takich jak porównania oparte na sygnaturach i niepodpisanych ma tyle dziwacznych i dziwacznych przypadków narożnych, że nie widzę, jak można mieć nadzieję, że poradzą sobie z nimi wszystkimi. Na przykład, biorąc pod uwagę 'uint32_t n', jakie byłoby zachowanie' (n-1) supercat

0

Makra zasadniczo ewentualnie dodawać stałą całkowitą sufiks takiego jak L, LL, U, UL, O UL ich argumentów, co zasadniczo sprawia, że ​​są prawie równoważne odpowiednim obsadzie, z wyjątkiem, że sufiks nie będzie nigdy spuszczony.

np UINT32_C(42000000000) (42 mld dolarów) na architekturze LLP64 zamieni 42000000000U, który będzie miał typ UL podlegającym rules explained here. Odpowiednia obsada, z drugiej strony ((uint32_t)42000000000), obciąłaby ją do uint32_t (unsigned int na LLP64).

Nie mogę wymyślić dobrego przykładu użycia, ale wyobrażam sobie, że może on być użyteczny w niektórych ogólnych makrach bitowych, które wymagają co najmniej X bitów do pracy, ale nie chcą usuwać żadnych dodatkowych bitów, jeśli użytkownik przekazuje coś większego.