Dlaczego wszyscy piszą zamiast standardowych typów C?

103

Jeśli chcesz korzystać z Qt , trzeba ogarnąć quint8, quint16i tak dalej.

Jeśli chcesz użyć wygadany , trzeba powitanie guint8, guint16i tak dalej.

Na Linuksie istnieją u32, s16i tak dalej.

uC / OS definiuje SINT32, UINT16i tak dalej.

A jeśli musisz użyć jakiejś kombinacji tych rzeczy, lepiej bądź przygotowany na kłopoty. Ponieważ na komputerze u32zostaną typedefd nad longi quint32będą typedefdni nad inti kompilator będzie narzekać .

Dlaczego wszyscy to robią, jeśli tak jest <stdint.h>? Czy to jakaś tradycja dla bibliotek?

Amomum
źródło
8
@Mehrdad w programowaniu mikrokontrolerów możesz mieć różne rzeczy. Na przykład na AVR Mega's (a co za tym idzie na słynnym Arduino) int jest 16 bitowy. To może być nieprzyjemna niespodzianka. Moim zdaniem „unsigned short” wymaga więcej wysiłku podczas pisania. I zawsze smuciło mnie używanie „unsigned char” dla oktetu <s> bajt </s>. Postać bez podpisu, naprawdę?
Amomum
2
@Mehrdad Chodzi o to, że nie możesz być pewien. Właśnie dlatego stdint.hzostał wymyślony.
glglgl
1
@glglgl: Oto inny sposób spojrzenia na problem: czy nie zadajesz dokładnie niewłaściwego pytania? Jeśli celujesz w wiele systemów, po co w pierwszej kolejności na sztywno zakodować liczbę bitów w kodzie? tj. dlaczego po prostu nie powiedzieć sizeof(int) * CHAR_BIT(na przykład) i użyć tego? Jeśli twój intjest zbyt mały, aby reprezentować twój zakres (np. Indeks tablicy), prawie na pewno nie powinieneś go używać int, ale coś w stylu size_t. Dlaczego miałoby to int32mieć większy sens? Jedynym sensem, jaki ma ustalona szerokość, jest komunikacja między systemami (np. Format pliku / sieci) ...
user541686
1
@Mehrdad Nie. Czasami mam wartości (na przykład z ADC lub cokolwiek innego), które muszę przechowywać. Wiem, że mają 16-bitową szerokość. Najlepiej więc użyć uint16_t(a może to fastlub leastwariant). Chodzi mi o to: te typy są wygodne w użyciu i mają swoją rację istnienia.
glglgl
1
@Mehrdad: Sugerowałbym, że - zakładając, że tworzenie kodu wysokiej jakości wydaje się warte twojego wysiłku - powinieneś zdefiniować własne typy funkcjonalne oznaczające sposób interakcji z moim API / resztą mojego kodu i zdefiniować je z przyczyn technicznych w zakresie „Techniczne” typy definicji, takie jak size_ti / lub uint64_t.
PJTraill

Odpowiedzi:

80

stdint.hnie istniało, kiedy te biblioteki były rozwijane. Więc każda biblioteka stworzyła własne typedefpliki.

Edward Karak
źródło
4
I okej, przypuszczam, że brak stdint.h jest dobrym powodem, ale dlaczego nawet dzisiaj te typy są ponad int, long i tak dla, a nie ponad stdint? To sprawi, że będą co najmniej wymienne
Amomum
25
@Amomum "Dlaczego Glib (który został opracowany na Linuksie) nie używał typedef dla Linuksa?" Chociaż „bazą domową” glib jest z pewnością Linux, z założenia jest to przenośna biblioteka. Zdefiniowanie własnych typów zapewnia przenośność: wystarczy dostosować niewielki nagłówek, który dopasowuje typy bibliotek do odpowiednich typów platform docelowych.
Peter - Przywróć Monikę
3
@Amomum Why Glib (który został opracowany w systemie Linux) ... Nie, nie był. Glib powstała droga przed jądrze Linux.
andy 256
5
@ andy256 „GLib” nie jest skrótem od „glibc”. To biblioteka, która oddzieliła się od gtk. Nie jest starszy niż Linux.
2
@ andy256: glib to 1998, linux to 1991. IOW, GLib powstał po Linuksie.
MSalters
40

W przypadku starszych bibliotek jest to potrzebne, ponieważ dany nagłówek ( stdint.h) nie istniał.

Wciąż jednak jest problem: te typy ( uint64_ti inne) są opcjonalną funkcją w standardzie. Zatem zgodna implementacja może nie zostać dostarczona wraz z nimi - a tym samym zmusić biblioteki do ich uwzględnienia w dzisiejszych czasach.

Ven
źródło
14
Te uintN_ttypy są opcjonalne, ale uint_leastN_ti uint_fastN_ttypy nie są.
Kusalananda
7
@Kusalananda: Niestety mają one ograniczoną przydatność.
Wyścigi lekkości na orbicie
16
Oczywiście dlatego, że są one jedynie opcją jest to, że nie są gwarantowane, że nie jest liczbą całkowitą typów z dokładnie tej liczby bitów. C nadal obsługuje architektury o raczej nieparzystych rozmiarach całkowitych.
celtschk
5
@LightnessRacesinOrbit: W jaki sposób mają one ograniczoną użyteczność? Muszę przyznać, że poza interfejsami sprzętowymi nie widzę powodu, dla którego potrzebowałbyś dokładnej liczby bitów, a nie tylko minimum, aby upewnić się, że wszystkie twoje wartości pasują.
celtschk
23
@Amomum Typedef to wymagane, jeśli implementacja ma typy spełniające wymagania: „Jeśli jednak implementacja zapewnia typy całkowite o szerokości 8, 16, 32 lub 64 bitów, bez bitów dopełnienia i (dla typów ze znakiem), które mają w uzupełnieniu do dwójki, będzie definiować odpowiadające im nazwy krojów pisma. " (cytat z N1570, 7.20.1.1 "Typy całkowite o dokładnej szerokości") Więc jeśli biblioteka standardowa ich nie ma, wydaje się, że biblioteka innej firmy też nie.
Eric M Schmidt
13

stdint.h został znormalizowany od 1999 roku. Jest bardziej prawdopodobne, że wiele aplikacji definiuje (efektywnie aliasy) typy, aby zachować częściową niezależność od podstawowej architektury maszyny.

Dają programistom pewność, że typy używane w ich aplikacjach odpowiadają założeniom projektu dotyczącym zachowania, które może nie odpowiadać standardowi języka lub implementacji kompilatora.

Praktyka ta znajduje odzwierciedlenie we wzorcu projektowym elewacji zorientowanym obiektowo i jest bardzo nadużywana przez programistów, którzy niezmiennie piszą klasy opakowujące dla wszystkich importowanych bibliotek.

Gdy elementy zgodne były znacznie mniej standardowe, a architektury maszyn mogły różnić się od 16-bitowych, 18-bitowych do 36-bitowych mainframe'ów o długości słowa, było to znacznie ważniejsze. Ta praktyka jest teraz znacznie mniej istotna w świecie konwergencji na 32-bitowych wbudowanych systemach ARM. Pozostaje problemem dla słabszych mikrokontrolerów z dziwnymi mapami pamięci.

Pekka
źródło
1
To prawda, stdint.hjest standaryzowany od 1999 r., Ale od jak dawna jest dostępny w praktyce? Ludzie ociągają się wdrażając i przyjmując nowe standardy, a podczas tego długiego okresu przejściowego stare metody są nadal konieczne.
Siyuan Ren,
1
Jednym z nieprzyjemnych haczyka stdint.hjest to, że nawet na platformach gdzie na przykład longi int32_tmają tę samą wielkość i reprezentacji, nie ma wymogu, że oddające int32_t*do long*przyniesie wskaźnik, który może w wiarygodny sposób uzyskać dostęp do int32_t. Nie mogę uwierzyć, że autorzy Standardu uważali za oczywiste, że typy zgodne z układem powinny być zgodne z aliasami, ale ponieważ nie zawracali sobie głowy stwierdzeniem, że autorzy gcc i IIRC twierdzą, że język zostałby ulepszony nawet przez ignorowanie aliasów w przypadkach, gdy jest to oczywiste.
supercat
2
@supercat - to prawdopodobnie warte przesłania jako errata do komisji C ... bo to jest bezsensownie głupie , delikatnie
mówiąc
@LThode: Aby komisja C uznała, że ​​jako błąd wymagałoby oficjalnego zadeklarowania zachowania clang i gcc jako tępego. Myślisz, że to się stanie? Najlepsze, na co można by oczekiwać (a IMHO logicznym sposobem postępowania) byłoby zdefiniowanie sposobów określania przez programy „trybów aliasingu”. Jeśli program mówi, że określa, że ​​może akceptować bardzo surowe reguły aliasingu, wówczas kompilator mógłby to wykorzystać, aby umożliwić optymalizacje wykraczające poza to, co jest obecnie możliwe. Jeśli program określa, że ​​wymaga reguł, które są nieco bardziej przyjazne programistom niż obecne ...
supercat.
... ale nadal pozwalałby na wiele przydatnych optymalizacji, wtedy kompilator mógłby wygenerować kod -fno-strict-alias, który byłby znacznie wydajniejszy niż byłby możliwy z , ale który nadal działałby. Nawet gdyby nie istniała baza kodu, żaden pojedynczy zestaw reguł nie byłby w stanie zapewnić optymalnej równowagi optymalizacji i semantyki dla wszystkich aplikacji, ponieważ różne aplikacje mają różne potrzeby. Dodaj istniejącą bazę kodów, a potrzeba różnych trybów powinna być jasna.
supercat
3

Masz więc możliwość wpisania wartości char na int.

Jeden z "horrorów związanych z kodowaniem" wspomniał, że jeden nagłówek firmy zawierał punkt, w którym programista chciał wartości logicznej, a znak był logicznym rodzimym typem zadania, i tak napisał typedef bool char. Później ktoś znalazł liczbę całkowitą jako najbardziej logiczny wybór i napisał typedef bool int. Rezultat, na wieki przed Unicode, był praktycznie typedef char int.

Myślę, że całkiem sporo przyszłościowego myślenia i kompatybilności.

Christos Hayward
źródło