Чому bool займає 4 байти
Чи є bool/char allocation 4 bytes instead of 1?
I'm trying to load a struct properly which has 1 char as a bool. Це виглядає як він повинен працювати добре, але якщо я printf data на bool it fails because it reads 4 bytes instead of 1.
typedef struct <char magic[8]; u32 version; bool updatable; u64 filetime; u32 region; u32 numentries; u32 fs1; u32 fs2; u8 *zonedata; >fastfile; int main(int argc, char **args) < if(!args[1]) return -1; u64 file_size; get_file_size(args[1], &file_size); u8 * file_data = new u8 [file_size]; read_file(args[1], file_data, file_size); //ignore це just reading data fastfile* ff = (fastfile *)(file_data + 0); //this is where I setup my struct according to file data >Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00E7C910 49 57 66 66 75 31 30 30 00 00 01 00 ÊÌ 00E7C920 3F 53 50 A3 40 00 00 00 02 00 00 00 00 00 03 5B ?SP£@. [ 00E7C930 78 DA EC 5D 09 7C 13 C5 FE DF A6 94 9B 02 0A 72 xÚì].|.Åþߦ”›..r як ви можете повідомити про те, що файл часу є в 0xE7C920 усвідомлює, що в 0xE7C91D будь-які думки про те, як може отримати це в роботі, як це зробити? або чи не буде працювати, що означає, що гравці будуть 4 bytes long?
Який розмір логічного значення C #? Невже це займає 4 байти?
У мене є дві структури з масивами байтів та логічних значень:
using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential, Pack = 4)] struct struct1 < [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] values; > [StructLayout(LayoutKind.Sequential, Pack = 4)] struct struct2 < [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public bool[] values; > class main < public static void Main( ) < Console.WriteLine("sizeof array of bytes: "+Marshal.SizeOf(typeof(struct1))); Console.WriteLine("sizeof array of bools: " + Marshal.SizeOf(typeof(struct2))); Console.ReadKey(); > > Це дає мені наступний результат:
sizeof array of bytes: 3 sizeof array of bools: 12 Здається, що a boolean займає 4 байти пам'яті. В ідеалі a boolean займатиме лише один біт (false або true, 0 або 1 і т. д.).
Що тут відбувається? Невже boolean типаж такий неефективний?
Це одне з найіронічніших зіткнень у битві за причини утримання: дві відмінні відповіді Джона і Ганса щойно дали його, хоча відповіді на це питання, як правило, майже повністю ґрунтуватимуться на думках, а не на фактах, засланнях, або конкретний досвід.
@TaW: Я припускаю, що близькі голоси були викликані не відповідями, а вихідним тоном ВП, коли вони вперше запитали - вони явно мали намір почати бійку і прямо показали це в тепер віддалених коментарях. Більшість сміття захована під килим, але подивіться історію змін, щоб зрозуміти, що я маю на увазі.
Відповіді:
Тип bool має мінливу історію з безліччю несумісних варіантів мовних середовищ. Це почалося з історичного вибору дизайну, зробленого Деннісом Річі, хлопцем, який винайшов мову C. Він не мав типу bool , альтернативою була int, де значення 0 становило брехня, а будь-яке інше значення вважалося істинним .
Цей вибір був перенесений у Winapi, основна причина використання pinvoke, у нього є typedef, для BOOL якого є псевдонімом ключового слова int компілятора C. Якщо ви не використовуєте явний атрибут [MarshalAs], то логічне значення C # перетворюється на BOOL, створюючи таким чином поле довжиною 4 байти.
Що б ви не робили, оголошення вашої структури має відповідати вибору середовища виконання, зробленому мовою, з якою ви взаємодієте. Як уже зазначалося, BOOL для winapi, але більшість реалізацій C++ вибирають байт , більшість взаємодії COM Automation використовують VARIANT_BOOL, що є коротким .
Фактичний розмір C#bool складає один байт. Сильна мета розробки CLR - те, що ви можете дізнатися. Макет - це деталь реалізації, яка дуже залежить від процесора. Процесори дуже прискіпливі до типів змінних та їх вирівнюванню, неправильний вибір може суттєво вплинути на продуктивність та викликати помилки часу виконання. Роблячи макет недоступним виявлення, .NET може надати універсальну систему типів, яка залежить від фактичної реалізації середовища виконання.
Іншими словами, ви завжди повинні маршалювати структуру під час виконання, щоб закріпити макет. На цьому етапі виконується перетворення з внутрішнього макет в макет взаємодії. Це може бути дуже швидко, якщо макет ідентичний, і повільним, коли поля необхідно переупорядкувати, оскільки для цього завжди потрібне створення копії структури. Технічний термін для цього - неперетворюваний , Передача неперетворюваної структури у власний код відбувається швидко, тому що маршалер pinvoke може просто передати покажчик.
Продуктивність також є основною причиною, через яку логічне значення не є поодиноким бітом. Є кілька процесорів, які забезпечують пряму адресацію бітів, найменша одиниця – байт. Для отримання біта з байта потрібно додаткова інструкція, яка надається безкоштовно. І він ніколи не буває атомним.
В іншому компіляторі C # не соромиться говорити вам, що він займає 1 байт, використовуйте sizeof(bool) . Це все ще не фантастичний провісник того, скільки байтів займає поле під час виконання, CLR також повинна реалізовувати модель пам'яті .NET, і вона обіцяє, що прості оновлення змінних є атомарними . Це вимагає, щоб змінні були правильно вирівняні в пам'яті, щоб процесор міг оновлювати їх за цикл шини пам'яті. Досить часто через це для bool потрібно 4 або 8 байтів у пам'яті. Додатковий відступ, доданий для забезпечення правильного вирівнювання наступного члена.
CLR фактично використовує те, що макет не може бути виявлений, він може оптимізувати макет класу та переупорядковувати поля, щоб мінімізувати відступи. Отже, скажімо, якщо у вас є клас із членом bool+int+bool, тоді він займе 1+(3)+4+1+(3) байта пам'яті, (3) - це заповнення, всього 12 байтів. 50% відходів. Автоматичне компонування змінюється на 1+1+(2)+4=8 байт. Тільки клас має автоматичне компонування, структури за замовчуванням мають послідовне компонування.
Ще похмуріше те, що для bool може знадобитися до 32 байтів у програмі C++, скомпільованої за допомогою сучасного компілятора C++, який підтримує набір інструкцій AVX. Що вимагає 32-байтового вирівнювання, змінна bool може містити 31 байт заповнення. Також основна причина, через яку джиттер .NET не дає інструкції SIMD, якщо явно не загорнути, він не може отримати гарантію вирівнювання.