uint8_t vs char yang tidak ditandatangani

231

Apa keuntungan menggunakan uint8_tlebih dari unsigned chardalam C?

Saya tahu bahwa pada hampir setiap sistem uint8_thanyalah sebuah typedef untuk unsigned char, jadi mengapa menggunakannya?

Lyndon White
sumber

Jawaban:

225

Ini mendokumentasikan maksud Anda - Anda akan menyimpan sejumlah kecil, bukan karakter.

Juga terlihat lebih bagus jika Anda menggunakan typedef lain seperti uint16_tatau int32_t.

Mark tebusan
sumber
1
Tidak jelas dalam pertanyaan awal apakah kita berbicara tentang tipe standar atau tidak. Saya yakin ada banyak variasi konvensi penamaan ini selama bertahun-tahun.
Mark Ransom
8
Secara eksplisit menggunakan unsigned charatau signed charmendokumentasikan maksudnya juga, karena tanpa hiasan charadalah apa yang menunjukkan Anda bekerja dengan karakter.
caf
9
Saya pikir tanpa hiasan unsignedadalah unsigned intdefinisi?
Mark Ransom
5
@endolith, menggunakan uint8_t untuk string tidak selalu salah, tapi ini pasti aneh.
Mark Ransom
5
@endolith, saya pikir saya bisa membuat case untuk uint8_t dengan teks UTF8. Memang, chartampaknya menyiratkan karakter, sedangkan dalam konteks string UTF8, mungkin hanya satu byte karakter multibyte. Menggunakan uint8_t dapat memperjelas bahwa seseorang tidak seharusnya mengharapkan karakter di setiap posisi - dengan kata lain bahwa setiap elemen dari string / array adalah bilangan bulat sembarang yang tidak boleh dibuatkan asumsi semantik apa pun. Tentu saja semua programmer C mengetahui hal ini, tetapi mungkin mendorong pemula untuk mengajukan pertanyaan yang tepat.
mentega
70

Hanya untuk menjadi bertele-tele, beberapa sistem mungkin tidak memiliki tipe 8 bit. Menurut Wikipedia :

Implementasi diperlukan untuk menentukan tipe integer lebar-tepat untuk N = 8, 16, 32, atau 64 jika dan hanya jika memiliki tipe apa saja yang memenuhi persyaratan. Tidak diperlukan untuk menentukan mereka untuk N lain, bahkan jika itu mendukung jenis yang sesuai.

Jadi uint8_ttidak dijamin ada, meskipun akan untuk semua platform di mana 8 bit = 1 byte. Beberapa platform yang disematkan mungkin berbeda, tetapi semakin jarang. Beberapa sistem dapat mendefinisikan charjenis menjadi 16 bit, dalam hal ini mungkin tidak akan ada jenis 8-bit dalam bentuk apa pun.

Selain masalah (kecil) itu, jawaban @Mark Ransom adalah yang terbaik menurut saya. Gunakan yang paling jelas menunjukkan untuk apa Anda menggunakan data.

Juga, saya berasumsi Anda maksudkan uint8_t(typedef standar dari C99 disediakan di stdint.hheader) daripada uint_8(bukan bagian dari standar apa pun).

Chris Lutz
sumber
3
@caf, karena penasaran belaka - dapatkah Anda menautkan ke deskripsi beberapa? Saya tahu mereka ada karena seseorang menyebutkan satu (dan ditautkan ke pengembang dokumen untuk itu) dalam sebuah comp.lang.c ++. Diskusi moderat tentang apakah jaminan tipe C / C ++ terlalu lemah, tapi saya tidak dapat menemukan utas itu lagi, dan selalu berguna untuk referensi bahwa dalam setiap diskusi serupa :)
Pavel Minaev
3
"Beberapa sistem dapat mendefinisikan tipe char menjadi 16 bit, dalam hal ini mungkin tidak akan ada tipe 8-bit dalam bentuk apa pun." - dan meskipun ada beberapa keberatan yang salah dari saya, Pavel telah menunjukkan dalam jawabannya bahwa jika char adalah 16 bit, maka bahkan jika kompilator menyediakan tipe 8 bit, ia tidak boleh memanggilnya uint8_t(atau mengetikkannya untuk itu). Ini karena tipe 8bit akan memiliki bit yang tidak digunakan dalam representasi penyimpanan, yang uint8_ttidak harus dimiliki.
Steve Jessop
3
Arsitektur SHARC memiliki kata-kata 32-bit. Lihat en.wikipedia.org/wiki/… untuk detailnya.
BCran
2
Dan DSP C5000 TI (yang ada di OMAP1 dan OMAP2) berukuran 16 bit. Saya pikir untuk OMAP3 mereka pergi ke seri C6000, dengan 8bit char.
Steve Jessop
4
Menggali ke N3242 - "Draft Kerja, Standar untuk Bahasa Pemrograman C ++", bagian 18.4.1 <cstdint> synopsis mengatakan - typedef unsigned integer type uint8_t; // optional Jadi, pada dasarnya, sebuah perpustakaan yang memenuhi standar C ++ tidak diperlukan untuk mendefinisikan uint8_t sama sekali (lihat komentar // opsional )
nightlytrails
43

Intinya adalah untuk menulis kode implementasi-independen. unsigned chartidak dijamin menjadi tipe 8-bit. uint8_tadalah (jika tersedia).

Semut
sumber
4
... jika ada pada suatu sistem, tapi itu akan sangat langka. +1
Chris Lutz
2
baik jika Anda benar-benar mengalami masalah dengan kode Anda tidak dikompilasi pada sistem karena uint8_t tidak ada, Anda dapat menggunakan find dan sed untuk secara otomatis mengubah semua kejadian uint8_t menjadi unsigned char atau sesuatu yang lebih berguna bagi Anda.
bazz
2
@ Bazz - tidak jika Anda menganggap itu adalah tipe 8-bit yang Anda tidak bisa - misalnya untuk membongkar data yang dikemas secara fashion oleh sistem jarak jauh. Asumsi implisit adalah bahwa alasan uint8_t tidak ada adalah pada prosesor di mana char lebih dari 8 bit.
Chris Stratton
melemparkan pernyataan tegas (sizeof (unsigned char) == 8);
bazz
3
@Bazz pernyataan salah saya takut. sizeof(unsigned char)akan kembali 1selama 1 byte. tetapi jika sistem char dan int berukuran sama, misalnya, 16-bit maka sizeof(int)juga akan kembali1
Toby
7

Seperti yang Anda katakan, " hampir setiap sistem".

charmungkin salah satu yang kurang mungkin berubah, tetapi begitu Anda mulai menggunakan uint16_tdan berteman, menggunakan uint8_tcampuran lebih baik, dan bahkan mungkin menjadi bagian dari standar pengkodean.

Justin Love
sumber
7

Dalam pengalaman saya ada dua tempat di mana kami ingin menggunakan uint8_t yang berarti 8 bit (dan uint16_t, dll) dan di mana kami dapat memiliki bidang yang lebih kecil dari 8 bit. Kedua tempat adalah tempat ruang penting dan kita sering perlu melihat dump data mentah ketika debugging dan harus dapat dengan cepat menentukan apa yang diwakilinya.

Yang pertama adalah dalam protokol RF, terutama dalam sistem pita sempit. Dalam lingkungan ini kita mungkin perlu mengemas informasi sebanyak mungkin ke dalam satu pesan. Yang kedua adalah dalam penyimpanan flash di mana kita mungkin memiliki ruang yang sangat terbatas (seperti pada sistem embedded). Dalam kedua kasus tersebut, kita dapat menggunakan struktur data dikemas di mana kompiler akan mengurus pengepakan dan membongkar untuk kita:

#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()

Metode mana yang Anda gunakan tergantung pada kompiler Anda. Anda mungkin juga perlu mendukung beberapa kompiler berbeda dengan file header yang sama. Ini terjadi pada sistem tertanam di mana perangkat dan server bisa sangat berbeda - misalnya Anda mungkin memiliki perangkat ARM yang berkomunikasi dengan server Linux x86.

Ada beberapa peringatan dengan menggunakan struktur yang dikemas. Gotcha terbesar adalah bahwa Anda harus menghindari dereferencing alamat anggota. Pada sistem dengan kata-kata selaras mutibyte, ini dapat menghasilkan pengecualian yang tidak selaras - dan coredump.

Beberapa orang juga akan khawatir tentang kinerja dan berpendapat bahwa menggunakan struktur yang dikemas ini akan memperlambat sistem Anda. Memang benar bahwa, di balik layar, kompiler menambahkan kode untuk mengakses anggota data yang tidak selaras. Anda dapat melihatnya dengan melihat kode assembly di IDE Anda.

Tetapi karena struktur yang dikemas paling berguna untuk komunikasi dan penyimpanan data maka data dapat diekstraksi menjadi representasi yang tidak dikemas ketika bekerja dengannya dalam memori. Biasanya kita tidak perlu bekerja dengan seluruh paket data dalam memori.

Berikut ini beberapa diskusi yang relevan:

paket pragma (1) atau __attribute__ ((sejajar (1)))) berfungsi

Apakah __attribute __ ((dikemas)) / #pragma paket gcc tidak aman?

http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html

Tereus Scott
sumber
6

Ada sedikit. Dari sudut pandang portabilitas, chartidak boleh lebih kecil dari 8 bit, dan tidak ada yang lebih kecil dari itu char, jadi jika implementasi C yang diberikan memiliki tipe integer 8-bit yang tidak ditandatangani, itu akan menjadi char. Atau, mungkin tidak ada sama sekali, di mana setiap typedeftrik diperdebatkan.

Ini dapat digunakan untuk mendokumentasikan kode Anda dengan lebih baik dalam arti bahwa Anda memerlukan 8-bit byte di sana dan tidak ada yang lain. Tetapi dalam praktiknya itu adalah ekspektasi yang wajar hampir di mana saja (ada platform DSP yang tidak benar, tetapi kemungkinan kode Anda berjalan di sana tipis, dan Anda bisa juga salah menggunakan statik statik di bagian atas program Anda pada platform seperti itu).

Pavel Minaev
sumber
7
@ Skizz - Tidak, standar mengharuskan unsigned charuntuk dapat menyimpan nilai antara 0 dan 255. Jika Anda dapat melakukannya dalam 4 bit, topiku tidak cocok untuk Anda.
Chris Lutz
1
"Ini akan menjadi sedikit lebih rumit" - rumit dalam arti bahwa Anda harus berjalan (berenang, naik pesawat, dll) sampai ke tempat penulis kompiler berada, menampar mereka di belakang kepala , dan membuat mereka menambah uint8_timplementasi. Saya bertanya-tanya, apakah kompiler untuk DSP dengan karakter 16bit biasanya diterapkan uint8_t, atau tidak?
Steve Jessop
6
Ngomong-ngomong, setelah dipikir-pikir, mungkin ini cara yang paling mudah untuk mengatakan "Aku benar-benar membutuhkan 8 bit" - #include <stdint.h>, dan gunakan uint8_t. Jika platform memilikinya, itu akan memberikannya kepada Anda. Jika platform tidak memilikinya, program Anda tidak akan dikompilasi, dan alasannya akan jelas dan langsung.
Pavel Minaev
2
Masih tidak ada cerutu, maaf: "Untuk tipe integer yang tidak ditandatangani selain dari unsigned char, bit dari representasi objek harus dibagi menjadi dua kelompok: bit nilai dan bit padding ... Jika ada bit nilai N, setiap bit akan mewakili yang berbeda kekuatan 2 antara 1 dan 2 ^ (N-1), sehingga objek jenis itu harus mampu mewakili nilai dari 0 hingga 2 ^ (N-1) menggunakan representasi biner murni ... Nama pengetik intN_t menunjuk sebuah tipe integer bertanda dengan lebar N, tanpa bit bantalan , dan representasi pelengkap dua. "
Pavel Minaev
1
Jika Anda hanya perlu modulo aritmatika, bitfield yang tidak ditandai akan baik-baik saja (jika tidak nyaman). Saat itulah Anda perlu, katakanlah, serangkaian oktet tanpa bantalan, saat itulah Anda SOL. Moral dari cerita ini tidak untuk kode untuk DSP, dan tongkat untuk tepat, jujur-untuk-Allah 8-bit Char arsitektur :)
Pavel Minaev
4

Itu sangat penting misalnya ketika Anda menulis penganalisa jaringan. header paket didefinisikan oleh spesifikasi protokol, bukan dengan cara kompiler C platform tertentu bekerja.

Wakil Presiden
sumber
kembali ketika saya bertanya ini saya mendefinisikan protokol sederhana untuk komunikasi melalui serial.
Lyndon White
2

Pada hampir setiap sistem saya telah bertemu char uint8_t == unsigned, tetapi ini tidak dijamin oleh standar C. Jika Anda mencoba menulis kode portabel dan ukurannya persis sama dengan ukuran memori, gunakan uint8_t. Kalau tidak, gunakan char yang tidak ditandatangani.

atlpeg
sumber
3
uint8_t selalu cocok dengan kisaran dan ukuran unsigned chardan bantalan (tidak ada) saat unsigned char 8-bit. Ketika unsigned chartidak 8-bit, uint8_ttidak ada.
chux - Reinstate Monica
@ chux, Apakah Anda memiliki referensi ke tempat yang tepat dalam standar di mana dikatakan itu? Jika unsigned charadalah 8-bit, yang uint8_tdijamin menjadi typedefdaripadanya dan bukan typedefdari tipe integer unsigned diperpanjang ?
hsivonen
@hsivonen "tempat yang tepat dalam standar di mana dikatakan itu?" -> Tidak - belum melihat ke 7.20.1.1. Ini mudah disimpulkan sebagai unsigned char/signed char/charjenis terkecil - tidak lebih kecil dari 8 bit. unsigned chartidak memiliki bantalan. Untuk uint8_tmenjadi, itu harus 8-bit, tidak ada bantalan, ada karena implementasi yang diberikan tipe integer: cocok dengan persyaratan minimal unsigned char. Mengenai "... dijamin menjadi typedef ..." sepertinya pertanyaan yang bagus untuk dikirim.
chux - Reinstate Monica