Яка перевага використання uint8_t
над unsigned char
C?
Я знаю, що майже в кожній системі uint8_t
є просто typedef для unsigned char
, так навіщо це використовувати?
Яка перевага використання uint8_t
над unsigned char
C?
Я знаю, що майже в кожній системі uint8_t
є просто typedef для unsigned char
, так навіщо це використовувати?
Відповіді:
Це документує ваш намір - ви будете зберігати невеликі числа, а не символ.
Крім того, це виглядає приємніше, якщо ви використовуєте інші typedefs, такі як uint16_t
або int32_t
.
unsigned char
або signed char
документуючи наміри теж, оскільки без реклами char
- це те, що показує, що ви працюєте з персонажами.
unsigned
був unsigned int
за визначенням?
char
схоже, йдеться про символ, тоді як у контексті рядка UTF8 це може бути лише один байт багатобайтового символу. Використання uint8_t може дати зрозуміти, що не слід очікувати символу в кожній позиції - іншими словами, кожен елемент рядка / масиву є довільним цілим числом, про яке не слід робити жодних семантичних припущень. Звичайно, це знають усі програмісти на C, але це може підштовхнути новачків до правильних питань.
Деякі системи, щоб бути педантичними, можуть не мати 8-бітового типу. Згідно Вікіпедії :
Потрібна реалізація для визначення цілочисельних типів точної ширини для N = 8, 16, 32 або 64, якщо і лише тоді, коли вона має будь-який тип, який відповідає вимогам. Не потрібно їх визначати для будь-яких інших N, навіть якщо вони підтримують відповідні типи.
Тому uint8_t
не гарантовано існування, хоча це буде для всіх платформ, де 8 біт = 1 байт. Деякі вбудовані платформи можуть бути різними, але це стає дуже рідко. Деякі системи можуть визначати char
типи, що мають 16 біт, і в цьому випадку, ймовірно, не буде 8-бітового типу.
Окрім цього (другорядного) питання, на мою думку , відповідь @Mark Ransom - найкраща. Використовуйте той, який найбільш чітко показує, для чого ви використовуєте дані.
Крім того, я припускаю, що ви мали на увазі uint8_t
(стандартний typedef від C99, наданий у stdint.h
заголовку), а не uint_8
(не є частиною будь-якого стандарту).
uint8_t
(або вводити до цього). Це тому, що тип 8 біт мав би невикористані біти у представленні сховища, яких uint8_t
не повинно бути.
typedef unsigned integer type uint8_t; // optional
Отже, по суті, бібліотека, що відповідає стандарту C ++, взагалі не потрібна для визначення uint8_t (див. Коментар // необов'язково )
Вся справа в тому, щоб написати незалежний від реалізації код. unsigned char
не гарантується, що це 8-бітний тип. uint8_t
є (якщо є).
sizeof(unsigned char)
повернеться 1
за 1 байт. але якщо системні char та int мають однаковий розмір, наприклад, 16-бітові, то sizeof(int)
також повернуться1
Як ви сказали, " майже кожна система".
char
це, мабуть, одна з менших шансів змінити, але як тільки ви почнете використовувати uint16_t
та дружити, uint8_t
краще використовуйте суміші, і навіть може бути частиною стандарту кодування.
На мій досвід, є два місця, де ми хочемо використовувати uint8_t, щоб означати 8 біт (і uint16_t тощо), і де ми можемо мати поля менше 8 біт. В обох місцях є місце, де важливий простір, і нам часто потрібно дивитися на неочищений дамп даних при налагодженні, і потрібно мати можливість швидко визначити, що це таке.
Перший - у протоколах РФ, особливо у вузькосмугових системах. У цьому середовищі нам може знадобитися запакувати якомога більше інформації в одне повідомлення. Друга - у флеш-пам’яті, де у нас може бути дуже обмежений простір (наприклад, у вбудованих системах). В обох випадках ми можемо використовувати структуру упакованих даних, в якій компілятор подбає про упаковку та розпакування для нас:
#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()
Який метод ви використовуєте, залежить від вашого компілятора. Також вам може знадобитися підтримка декількох різних компіляторів з однаковими файлами заголовків. Це відбувається у вбудованих системах, де пристрої та сервери можуть бути абсолютно різними - наприклад, у вас може бути пристрій ARM, який спілкується з сервером x86 Linux.
Існує кілька застережень із використанням упакованих структур. Найбільша проблема полягає в тому, що ви повинні уникати перенаправлення адреси члена. У системах з мутибайтовими вирівняними словами це може призвести до вирівнювання, яке не вирівнюється, - і коридору.
Деякі люди також будуть турбуватися про продуктивність і стверджують, що використання цих упакованих структур уповільнить вашу систему. Це правда, що поза кадром компілятор додає код для доступу до неприєднаних членів даних. Ви можете це бачити, дивлячись на код складання у вашому IDE.
Але оскільки упаковані структури є найбільш корисними для зв'язку та зберігання даних, то дані можуть бути вилучені в непакетоване представлення під час роботи з ним у пам'яті. Зазвичай нам не потрібно працювати з усім пакетом даних у пам'яті.
Ось відповідна дискусія:
pragma pack (1) ні __attribute__ ((вирівняний (1))) працює
Чи небезпечний __attribute __attribute __ ((упакований)) gcc / #pragma?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Тут мало. З точки зору портативності, вона char
не може бути меншою ніж 8 біт, і нічого не може бути меншим char
, тому, якщо дана реалізація C має непідписаний 8-бітний цілочисельний тип, це буде char
. Крім того, він може не мати його взагалі, і в цей момент будь-які typedef
трюки суперечать.
Це можна використовувати для кращого документування вашого коду в сенсі, що зрозуміло, що вам потрібні 8-бітні байти та нічого іншого. Але на практиці це вже розумне очікування практично в будь-якому місці (є платформи DSP, на яких це неправда, але шанси вашого коду там невисокі, і ви можете так само помилитися, використовуючи статичне затвердження у верхній частині вашої програми на така платформа).
unsigned char
щоб можна було утримувати значення між 0 і 255. Якщо ви можете це зробити в 4 біти, моя шапка знімається до вас.
uint8_t
до реалізації. Цікаво, чи компілятори для DSP з 16-бітовими символами зазвичай реалізують uint8_t
, чи ні?
#include <stdint.h>
і використовувати uint8_t
. Якщо платформа має її, вона передасть її вам. Якщо на платформі її немає, ваша програма не збиратиметься, а причина буде зрозумілою та зрозумілою.
Це дуже важливо, наприклад, коли ви пишете мережевий аналізатор. заголовки пакетів визначаються специфікацією протоколу, а не тим, як працює компілятор C певної платформи.
Практично в кожній системі, з якою я зустрічався, не підписаний знак uint8_t ==, але це не гарантується стандартом C. Якщо ви намагаєтеся написати портативний код і має значення саме того, який розмір пам'яті, використовуйте uint8_t. В іншому випадку використовуйте неподписані знаки.
uint8_t
завжди відповідає діапазону та розміру unsigned char
та прокладці (немає), коли unsigned char
8-бітний. Коли unsigned char
не є 8-бітовим, uint8_t
не існує.
unsigned char
це 8-біт, буде uint8_t
гарантовано буде typedef
їх , а не typedef
з розширеного цілого числа без знака типу ?
unsigned char/signed char/char
і найменший тип - не менше 8 біт. unsigned char
не має прокладки. Щоб uint8_t
це було, воно повинно бути 8-бітним, без прокладки, щоб існувати через цілий цілий тип, що відповідає: відповідає мінімальним вимогам unsigned char
. Щодо "... гарантовано, що буде typedef ..." виглядає як хороше запитання для публікації.