Подравняване на член на структурата в GCC

Пренасям проект msvc, който има няколко библиотеки и всяка библиотека има специфично подравняване на членове на структури. Използването на подравняване по подразбиране причини много фатални проблеми с неправилното подравняване и Google ми каза, че мога да разреша този проблем, като задам подравняване за всяка структура / клас / обединение ръчно с флага __attribute__ ((aligned (MY_ALIGN))), но има едно нещо, което ме притеснява:

Да кажем за простота, че проект A използва подравняване от 1 байт, а проект B, който активно използва функционалността на проект A и включва много от своите заглавки, има подравняване от 16 байта. Ще има ли проблем с това, или мисля твърде много и просто ще работи? Имам лошото предчувствие, че когато изграждам библиотека, компилаторът msvc задава подравняване за всяка структура във всички заглавки (без значение дали са включени в проект или са посочени от източници). Това истина ли е? И ако е така, моля, кажете ми как трябва да настроя подравняването да емулира настройката за подравняване на член на структурата на MSVC?


person Anonymous    schedule 20.07.2011    source източник
comment
Освен ако не използвате типове SIMD (SSE), наистина не би трябвало да имате проблеми, ако използвате подравняване по подразбиране. Ако все пак получите грешки, това е защото правите нещо ужасно в кода си, което трябва да бъде поправено.   -  person jalf    schedule 20.07.2011
comment
Е, SSE разширенията се използват широко и има много код, който изисква специфично подравняване...   -  person Anonymous    schedule 20.07.2011
comment
Като се има предвид SSE, трябва да можете да конфигурирате компилатора да извежда MOVUPS и други подобни, вместо MOVAPS. Това решава проблема ви по вече преносим начин. Втора опция би била да използвате библиотека, която фиксира подравняване на 16 байта, трета би била да създадете/интегрирате такава библиотека от вашия проект. Независимо от това, трябва да коригирате подравняването на структурите и членовете вътре в заглавките, а не в настройките на проекта или флаговете на компилатора.   -  person dascandy    schedule 20.07.2011
comment
мисълта ми е, че нормалните типове се разпределят правилно от компилатора, освен ако изрично не го нарушите (чрез извършване на опасни прехвърляния, които разчитат на недефинирано поведение). Така че, ако получите грешки при подравняване извън на SSE нещата, това може да сочи към по-дълбок проблем с вашия код   -  person jalf    schedule 20.07.2011
comment
Dascandy, можеш ли да ми кажеш как трябва да конфигурирам компилатора на Apple GCC 4.2.1?   -  person Anonymous    schedule 20.07.2011
comment
изобщо не използвайте -fpack-struct, оставете компилатора да определи как да подравнява нещата. За типовете SSE не съм сигурен, че GCC дори генерира SSE ходове. Ако използвате SSE библиотека, тя трябва да се погрижи за подравняването с __attribute__((aligned(16))) или подобен. За подравняването можете да приемете, че всеки бит от данни, който започва с естественото си подравняване, няма да бъде подплатен от компилатор. За системи, ориентирани към производителност, това все още е вярно, но само за типове, по-големи или равни на неговия базов тип (int). Така че двойните винаги са подравнени по 8 байта и няма да получат подложка, ако са, но два char[3] могат да получат байт подложка   -  person dascandy    schedule 20.07.2011


Отговори (2)


Не мисля, че трябва да има проблем с това. Само помнете, че неподравненият достъп (минимум 4 байта мисля, че на повечето системи) ще ви струва (въпреки че спестявате място, макар и не много в някои ситуации). Самите структури имат атрибута и компилаторът ще извърши цялата аритметика на указателя, така че стига заглавките да не се забъркват с дефинициите един на друг, трябва да е наред.

person Jesus Ramos    schedule 20.07.2011
comment
може да зависи от архитектурата, за която компилирате. Някои процесори не позволяват неподравнен достъп до определени типове променливи (напр. дори адресите за int достъп са необходими, адресите за double трябва да се делят на 8, ...). Освен това не виждам никакви проблеми, стига подравняването да се използва за структурите, които се нуждаят от него и не е глобално включено. - person Tobias Langner; 20.07.2011
comment
Да, това беше моята гледна точка (неподравненият достъп не е голяма работа). Докато подравняването не се отменя някъде, всичко е наред. Лично аз не се занимавам с това, тъй като компилаторът знае най-добре. - person Jesus Ramos; 20.07.2011
comment
Благодаря ви за отговорите, но проектът се пренася към платформата Mac OS X, където неправилното подравняване причинява повреда на приложението, така че неподравненият достъп всъщност е много голям проблем... - person Anonymous; 20.07.2011
comment
Това е добре, можете да запазите подравняването си, което работи, стига заглавките да не се сблъскват едно с друго. - person Jesus Ramos; 20.07.2011
comment
Благодаря, Исусе! :) Можете ли да ми кажете какво имате предвид под сблъсък на заглавки? Заглавките на проект A са включени в източниците на проект B и обектите, дефинирани в тях, се използват широко в проект B... - person Anonymous; 20.07.2011
comment
Под сблъсък имам предвид, ако дефинирам struct myStruct1 с подравняване 1 и след това в заглавка B предефинирам подравняването до 4, което може да причини проблеми, но намирам това за много малко вероятно. - person Jesus Ramos; 21.07.2011

Първо, всяко заглавие #include във вашия изходен файл получава процеси буквално, няма значение дали е в същия проект или не.

Определено може да доведе до някои проблеми. Например, проект A дефинира структура и подравнява всички нейни членове към граница на байт (пакетиран) и експортира функция, приемаща указател към тази структура. След това, ако проект B по някаква причина е компилиран в такава среда, че същата структура се подравнява по различен начин, това би направило невъзможно предаването на адрес на екземпляр на този struct директно към тази експортирана рутина. Те имат различни sizeofs поне в A и B.

Простото правило е следното:
1) ако трябва да взаимодействате с някаква външна компилирана библиотека, трябва да се уверите, че подравняването на структурата е в съответствие с това, използвано от компилатора на библиотеката. Това се отнася за структурите, присъстващи в заглавките на библиотеката. Добрите библиотеки се опитват да сведат до минимум усилието, като предоставят #pragma за някои компилатори, за да осигурят правилното подравняване.
2) ако използвате структури в някой ваш проект, можете да го оставите, просто напишете преносим код, който не разчита при някакво конкретно подравняване ще свърши работа.

person unkulunkulu    schedule 20.07.2011