Jakie są zalety korzystania z uint8_t
ciągu unsigned char
w C?
Wiem, że w prawie każdym systemie uint8_t
jest po prostu typedef unsigned char
, więc po co go używać?
Jakie są zalety korzystania z uint8_t
ciągu unsigned char
w C?
Wiem, że w prawie każdym systemie uint8_t
jest po prostu typedef unsigned char
, więc po co go używać?
Odpowiedzi:
Dokumentuje to twoją intencję - będziesz przechowywać małe liczby zamiast postaci.
Wygląda też ładniej, jeśli używasz innych typów czcionek, takich jak uint16_t
lub int32_t
.
unsigned char
lub signed char
dokumentuje również intencję, ponieważ bez ozdoby char
jest to, co pokazuje, że pracujesz z postaciami.
unsigned
jest unsigned int
z definicji?
char
wydaje się , że implikuje znak, podczas gdy w kontekście ciągu UTF8 może to być tylko jeden bajt znaku wielobajtowego. Użycie uint8_t może wyjaśnić, że nie należy oczekiwać znaku na każdej pozycji - innymi słowy, że każdy element łańcucha / tablicy jest dowolną liczbą całkowitą, o której nie należy przyjmować żadnych semantycznych założeń. Oczywiście wszyscy programiści C wiedzą o tym, ale może popchnąć początkujących do zadawania właściwych pytań.
Żeby być pedantycznym, niektóre systemy mogą nie mieć typu 8-bitowego. Według Wikipedii :
Implementacja jest wymagana do zdefiniowania typów liczb całkowitych o dokładnej szerokości dla N = 8, 16, 32 lub 64 tylko wtedy, gdy ma dowolny typ spełniający wymagania. Nie jest wymagane ich zdefiniowanie dla żadnego innego N, nawet jeśli obsługuje odpowiednie typy.
Nie uint8_t
ma gwarancji, że będzie istnieć, chociaż będzie to miało miejsce na wszystkich platformach, na których 8 bitów = 1 bajt. Niektóre platformy wbudowane mogą się różnić, ale staje się to bardzo rzadkie. Niektóre systemy mogą definiować char
typy na 16 bitów, w takim przypadku prawdopodobnie nie będzie żadnego typu 8-bitowego.
Poza tym (mniejszym) problemem, odpowiedź @ Mark Ransom jest moim zdaniem najlepsza. Użyj tego, który najlepiej pokazuje, do czego używasz danych.
Zakładam również, że miałeś na myśli uint8_t
(standardowy typedef z C99 podany w stdint.h
nagłówku), a nie uint_8
(nie jest częścią żadnego standardu).
uint8_t
(lub wpisywać do niego). Wynika to z faktu, że typ 8-bitowy miałby nieużywane bity w reprezentacji pamięci, których uint8_t
nie może mieć.
typedef unsigned integer type uint8_t; // optional
Zasadniczo biblioteka zgodna ze standardem C ++ nie jest wcale potrzebna do zdefiniowania uint8_t (patrz komentarz // opcjonalny )
Chodzi o to, aby napisać kod niezależny od implementacji. unsigned char
nie jest gwarantowanym typem 8-bitowym. uint8_t
jest (jeśli dostępne).
sizeof(unsigned char)
zwróci 1
1 bajt. ale jeśli char i int systemu są tego samego rozmiaru, na przykład 16-bitów, to sizeof(int)
również zwróci1
Jak powiedziałeś, „ prawie każdy system”.
char
jest prawdopodobnie jedną z mniej prawdopodobnych zmian, ale kiedy zaczniesz używać uint16_t
i znajomych, uint8_t
lepiej używasz mieszania, a nawet może być częścią standardu kodowania.
Z mojego doświadczenia wynika, że istnieją dwa miejsca, w których chcemy używać uint8_t w celu oznaczenia 8 bitów (i uint16_t itp.) I gdzie możemy mieć pola mniejsze niż 8 bitów. Oba miejsca mają znaczenie dla przestrzeni i często musimy spojrzeć na surowy zrzut danych podczas debugowania i musimy być w stanie szybko określić, co to reprezentuje.
Pierwszy dotyczy protokołów RF, szczególnie w systemach wąskopasmowych. W tym środowisku może być konieczne spakowanie jak największej ilości informacji w jedną wiadomość. Drugi dotyczy pamięci flash, w której możemy mieć bardzo ograniczoną przestrzeń (na przykład w systemach wbudowanych). W obu przypadkach możemy użyć struktury danych spakowanych, w których kompilator zajmie się dla nas pakowaniem i rozpakowywaniem:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
Wybór metody zależy od kompilatora. Konieczne może być także wsparcie kilku różnych kompilatorów z tymi samymi plikami nagłówkowymi. Dzieje się tak w systemach wbudowanych, w których urządzenia i serwery mogą być zupełnie inne - na przykład możesz mieć urządzenie ARM, które komunikuje się z serwerem Linux x86.
Istnieje kilka zastrzeżeń dotyczących używania upakowanych struktur. Największym problemem jest to, że musisz unikać dereferencji adresu członka. W systemach ze słowami wyrównanymi mutibajtami może to spowodować niepoprawny wyjątek i zrzut rdzeniowy.
Niektórzy ludzie martwią się również wydajnością i twierdzą, że użycie tych spakowanych struktur spowolni twój system. Prawdą jest, że za kulisami kompilator dodaje kod, aby uzyskać dostęp do nieprzystosowanych elementów danych. Możesz to zobaczyć patrząc na kod asemblera w twoim IDE.
Ponieważ jednak upakowane struktury są najbardziej przydatne do komunikacji i przechowywania danych, dane można wyodrębnić do niepakowanej reprezentacji podczas pracy z nimi w pamięci. Zwykle i tak nie musimy pracować z całym pakietem danych w pamięci.
Oto kilka istotnych dyskusji:
pragma pack (1) ani __attribute__ ((wyrównany (1))) działa
Czy pakiet gcc __attribute __ ((pack)) / #pragma jest niebezpieczny?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Jest mało Z punktu widzenia przenośności char
nie może być mniejszy niż 8 bitów i nic nie może być mniejsze niż char
, więc jeśli dana implementacja C ma 8-bitową liczbę całkowitą bez znaku, będzie char
. Alternatywnie może nie mieć go wcale, w którym to momencie jakiekolwiek typedef
sztuczki są dyskusyjne.
Można go użyć do lepszego udokumentowania kodu w tym sensie, że jest jasne, że potrzebujesz tam 8-bitowych bajtów i nic więcej. Ale w praktyce jest to rozsądne oczekiwanie praktycznie już wszędzie (istnieją platformy DSP, na których to nieprawda, ale szanse na uruchomienie tam kodu są niewielkie, a równie dobrze możesz popełnić błąd, używając statycznego potwierdzenia na górze programu na taka platforma).
unsigned char
zdolności do przechowywania wartości od 0 do 255. Jeśli możesz to zrobić w 4 bitach, moja czapka jest dla ciebie.
uint8_t
do implementacji. Zastanawiam się, czy kompilatory dla procesorów DSP z 16-bitowymi znakami zwykle implementują uint8_t
, czy nie?
#include <stdint.h>
i użycia uint8_t
. Jeśli platforma ma to, da ci ją. Jeśli platforma go nie ma, twój program się nie skompiluje, a przyczyna będzie jasna i prosta.
Jest to naprawdę ważne na przykład podczas pisania analizatora sieci. nagłówki pakietów są definiowane przez specyfikację protokołu, a nie sposób działania kompilatora C dla konkretnej platformy.
Niemal na każdym systemie poznałem uint8_t == unsigned char, ale nie gwarantuje tego standard C. Jeśli próbujesz napisać przenośny kod i ma on znaczenie, dokładnie jaki jest rozmiar pamięci, użyj uint8_t. W przeciwnym razie użyj znaku bez znaku.
uint8_t
zawsze dopasowuje zakres i rozmiar unsigned char
oraz dopełnianie (brak), gdy unsigned char
jest 8-bitowe. Kiedy unsigned char
nie jest 8-bitowy, uint8_t
nie istnieje.
unsigned char
jest 8-bitowy, czy uint8_t
na pewno jest typedef
nim, a nie typedef
typu rozszerzonej liczby całkowitej bez znaku ?
unsigned char/signed char/char
najmniejszy typ - nie mniejszy niż 8 bitów. unsigned char
nie ma wyściółki. Aby uint8_t
być, musi być 8-bitowy, bez dopełnienia, istnieje z powodu implementacji podanej typu liczby całkowitej: spełniającej minimalne wymagania unsigned char
. Jeśli chodzi o „... gwarantujemy, że będzie to typedef ...” wygląda na dobre pytanie do opublikowania.