Вирівнювання даних

Вирівнювання (alignment) відповідає розміщенню порції даних в памяті Кажуть, що змінна має природне вирівнювання (naturally aligned), якщо вона знаходиться в памяті за адресою, значення якого кратне розміру цієї змінної Наприклад, змінна 32-розрядного типу даних має природне вирівнювання, якщо вона знаходиться в памяті по адресою, кратному 4 байт (тобто два молодших біта адреси рівні нулю) Таким чином, структура дані розміром 2n    байт повинна зберігатися в памяті за адресою, молодші n бітів якого дорівнюють нулю

Для деяких апаратних платформ існують суворі вимоги щодо вирівнювання даних На деяких системах, зазвичай RISC, завантаження неправильно вирівняних даних призводить до генерації системного переривання (trap), помилки, яку можна обробити На інших системах з неприродно вирівнюємо даними можна працювати, але це призводить до зменшення вироб-

водительности При написанні стерпного коду необхідно запобігати проблеми, повязані з вирівнюванням, а дані всіх типів повинні мати природне вирівнювання

Як уникнути проблем з вирівнюванням

Компілятор зазвичай запобігає проблеми, повязані з вирівнюванням, шляхом природного вирівнювання всіх типів даних Насправді, розробники ядра зазвичай не повинні займатися проблемами, повязаними з вирівнюванням, про це повинні дбати розробники компілятора gcc Однак такі проблеми все ж можуть виникати, коли розробнику доводиться виконувати операції з покажчиками і здійснювати доступ до даних, не враховуючи того, як компілятор виконує операції доступу до даних

Доступ до адреси памяті, для якого виконано вирівнювання, через перетворений покажчик на тип даних більшого розміру може привести до проблем вирівнювання (для різних апаратних платформ це може виявлятися по-різному) Наступний код може привести до зазначеної проблеми

char dog [10]

char *p = &ampdog[1]

unsigned long 1 = * (unsigned long *)p

У цьому прикладі покажчик на дані типу unsigne d cha r використовується, як покажчик на тип unsigne d long, що може призвести до того, що 32-розрядне значення типу unsigne d lon g буде зчитуватися з памяті за адресою, що не кратному чотирьом

Якщо ви думаєте: Навіщо мені це може бути потрібно ,то ви, швидше за все, мають рацію Проте, якщо ми таке зробили тільки що, то таке можна зробити і хто-небудь ще, тому необхідно бути уважними Приклади, які зустрічаються в реальному життя, не обовязково будуть так само очевидні

Вирівнювання нестандартних типів даних

Як вже вказувалося, при вирівнюванні адресу стандартного типу даних повинен бути кратним розміром цього типу Нестандартні (складні) типи даних підкоряються наступним правилам вирівнювання

• Вирівнювання масиву виконується так само, як і вирівнювання типу даних першого елемента (всі інші елементи будуть коректно вирівняні автоматично)

• Вирівнювання обєднання (union) відповідає вирівнюванню найбільшого, за розміром, типу даних з тих, які включені в обєднання

• Вирівнювання структури відповідає вирівнюванню найбільшого, за розміром, типу даних серед типів всіх полів структури

У структурах також можуть використовуватися різні способи заповнення (padding)

Заповнення структур

Структури заповнюються таким чином, щоб кожен її елемент мав природне вирівнювання Наприклад, розглянемо наступну структуру даних на 32разрядной машині

struct animal_struct {

char dog / * 1 байт * / unsigned longcat / * 4 байт * / unsigned shortpig / * 2 байт * /

charfox / * 1 байт * /

}

Ця структура даних у памяті виглядає не так, що повязано з необхідністю природного вирівнювання У памяті компілятор створює структуру даних, яка схожа на наступну

struct animal_struct {

char dog / * 1 байт * / u8 __ pad0 [3] / * 3 байт * / unsigned long cat / * 4 байт * / unsigned short pig / * 2 байт * /

char fox / * 1 байт * /

u8         padl / * 1 байт * /

}

Змінні заповнення вводяться для того, щоб забезпечити природне вирівнювання всіх елементів структури Перша змінна заповнення вводить додаткові витрати памяті для того, щоб розмістити поле ca t на кордоні

4-байтового адреси Друга змінна використовується для вирівнювання розміру самої структури Додатковий байт гарантує, що розмір структури буде кратний чотирьом байтам і що кожен елемент масиву таких структур буде мати природне вирівнювання

Слід звернути увагу, що вираз sizeo f (foo_struct) дорівнює значенню 12 для будь-якого примірника цієї структури на більшості 32-розрядних апаратних платформ Компілятор мови С автоматично додає елементи заповнення, щоб гарантувати необхідне вирівнювання

Часто є можливість переставити поля структури так, щоб уникнути необхідності заповнення Це дозволяє отримати правильно вирівняні дані без введення додаткових елементів заповнення та, відповідно, структуру меншого розміру

struc t  animal  struc t  {

unsigned long cat / * 4 байта * / unsigned short pig/*   2  байта * / char dog / * 1 байт * /

char fox / * 1 байт * /

}

Ця структура даних має розмір 8 байт Однак не завжди існує можливість перестановки елементів структури місцями і зміни визначення струк-

тури Наприклад, якщо структура поставляється як частина стандарту, або вже використовується в існуючому коді, то порядок проходження полів міняти не можна Іноді, з деяких причин, може знадобитися спеціальний порядок проходження полів структури, наприклад спеціальне вирівнювання змінних для оптимізації попадання в кеш Зауважимо, що, відповідно до стандарту ANSI С, компілятор ніколи не повинен міняти порядок проходження полів у структурах5 даних – цим правом володіє тільки програміст

Розробники ядра повинні враховувати особливості заповнення при обміні структурами даних: передача структур по мережі або безпосереднє збереження на диск, тому що необхідне заповнення може бути різним для різних апаратних платформ Це одна з причин, по якій в мові програмування С немає оператора порівняння структур Память, яка використовується для заповнення структур даних, може містити випадкову інформацію, що унеможливлює побайтово порівняння структур Розробники мови, програмування С правильно зробили, що залишили рішення задачі порівняння структур на розсуд програміста, який може створювати свої функції порівняння в кожному конкретному випадку, щоб використовувати особливості побудови конкретних структур

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*