Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос на счет выравнивания переменных
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
AirDevil
Всем привет!

Код
u32 func(char * array, u32 * A)
{
    *A = 2;
    return *A;
}


Иногда возникает такая проблема, если А не выравнена по слову, попадает смещенная величина.
Вот пример:

В самом начале:
____word___________wordA____
| 00 00 00 00 |____| 00 00 00 00 |

Должно получиться после присваивания:
____word___________wordA____
| 00 00 00 00 |____| 02 00 00 00 |

А получается так:
____word___________wordA____
| 00 00 00 02 |____| 00 00 00 00 |

Кто как борет это?
Компилятор GCC.
demiurg_spb
Для какой архитектуры компилятор?
Вы что-то путаете.
Для начала вы определитесь какой на вашем таргете порядок байт (big/little)endian.
Поэкспериментируйте в отладчике. И всё встанет на свои места.
А отсутствие выравнивания внутри стандартных встроенных типов данных быть не может никогда!
Выравнивание есть всегда и оно зависит от разрядности таргета и от настроек компилятора и всяких там pragma pack для структур.
zltigo
Цитата(AirDevil @ Oct 19 2009, 18:05) *
Кто как борет это?

Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.
Второе, если уж где-то реально нужно, то контролировать полученный адрес на выравненность и использовать для таких случаев (или тупо всегда) копирование областей памяти.


Цитата(demiurg_spb @ Oct 19 2009, 18:28) *
Для какой архитектуры компилятор?

ARM, например. Не AVR, не x86....
AirDevil
Цитата(zltigo @ Oct 19 2009, 20:05) *
Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.

Трудно не согласиться.

Цитата(zltigo @ Oct 19 2009, 20:05) *
Второе, если уж где-то реально нужно, то контролировать полученный адрес на выравненность и использовать для таких случаев (или тупо всегда) копирование областей памяти.

В принципе и делал когда глюки были. Выравнивание с помощью memcpy и всё. Я думал, что возможно еще есть пути. Оказывается, что нет и вижу что делал правильно.

С П А С И Б О ! ! !
AHTOXA
Цитата(zltigo @ Oct 19 2009, 23:05) *
Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.


В чём "говнокодность" присваивания *A = 2 при условии, что A - это указатель на u32? Автор наверняка умолчал о хитром способе вызова функции - это да. А в приведённом коде не вижу никакого криминала.
zltigo
Цитата(AHTOXA @ Oct 19 2009, 22:44) *
при условии, что A - это указатель на u32

Да, это указатель на u32, но не выровненный, а находящийся, например, в каком-нибудь буфере передачи.
GetSmart
Цитата(zltigo @ Oct 20 2009, 02:13) *
Да, это указатель на u32, но не выровненный, а находящийся, например, в каком-нибудь буфере передачи.

Для этого в IARе нужно было всего-то объявить невыравненный тип u32_unalign и вообще не напрягаться
Код
#pragma pack(push, 1)
typedef u32 u32_unalign;
#pragma pack(pop)

u32 func(u08 * array, u32_unalign * A)
{
    u32 tmp = *(u32_unalign *)array;
    *A = tmp;
    return tmp;
}


Работает ли это в GCC ? Ессно изменив прагму.
_Pasha
Цитата(GetSmart @ Oct 19 2009, 23:40) *
Работает ли это в GCC ? Ессно изменив прагму.

Например:
Код
typedef unsigned int u32_unalign __attribute__ ((aligned (1)));

Все-же атрибуты веселее прагм в большинстве случаев. laughing.gif
zltigo
Цитата(GetSmart @ Oct 19 2009, 23:40) *
Для этого..
#pragma pack(push, 1)
typedef u32 u32_unalign;
#pragma pack(pop)

Цитата(_Pasha @ Oct 20 2009, 00:04) *
Например:
typedef unsigned int u32_unalign __attribute__ ((aligned (1)));


Даже не знаю, сметься, плакать, или спросить где Вы оба берете такую траву? Можно я помолчу?
GetSmart
От зараза, не сработала biggrin.gif
Я обычно через структуру или union работаю (в IARе), а тут решил "сэкономить" и даже не проверил.
Код
#pragma pack(push, 1)
typedef union
{ float f;
  u32 l;
  u16 w[2];
  u08 b[4];
} u32_unalign;
#pragma pack(pop)

Звиняюсь, за спешку. Но этот вариант уже точно правильно работает и при записи и при чтении невыравненных переменных (long/short/float).

Хотя вопрос к тем, кто знает - почему "typedef u32 u32_unalign;" внутри прагмы не работает?
zltigo
Цитата(GetSmart @ Oct 20 2009, 01:43) *
Но этот вариант уже точно правильно работает...

Чем дальше в лес, тем больше дров sad.gif. Сколько еще "идей"? Может лучше спать, а поутру почитать, что за прагма pack и для чего она годится?
GetSmart
Цитата(zltigo @ Oct 20 2009, 05:14) *
Чем дальше в лес, тем больше дров sad.gif. Сколько еще "идей"? Может лучше спать, а поутру почитать, что за прагма pack и для чего она годится?

smile.gif
Вы удивитесь, но она не только отключает выравнивание многобайтных переменных внутри структур/юнионов, но и организует побайтный (при pack(1)) доступ ко всем полям внутри структур/юнионов. Я проверил в ИАРе - при обращении к полю l например (в описанном мной юнионе) чтение и запись происходят побайтовые. Я так думаю, что автору темы именно это и надо было.
rezident
Цитата(GetSmart @ Oct 20 2009, 04:43) *
Хотя вопрос к тем, кто знает - почему "typedef u32 u32_unalign;" внутри прагмы не работает?
Потому что
Цитата("IAR C/C++ Development Guide Compiling and linking for Advanced RISC Machines Ltd’s ARM® Core")
Pragma directive | Description
-------------------------------------------------------------------------------
pack | Specifies the alignment of structures and union members
А отдельные переменные и так всегда выровнены.
GetSmart
Отдельные переменные не всегда выравнены. В посте у автора темы параметром передаётся ссылка на u32. Вполне "законно" можно передать туда адрес переменной u32, находящейся в структуре с невыравненными переменными. ИАР при этом выдаст варнинг, что это опасно. GCC не знаю выдаст или нет. Так вот, если бы можно было создать тип u32 с атрибутом побайтового обращения, то не пришлось бы извращаться с юнионом. Отсюда вопрос - можно ли?
rezident
Цитата(GetSmart @ Oct 20 2009, 06:21) *
Вполне "законно" можно передать туда адрес переменной u32, находящейся в структуре с невыравненными переменными.
Кто так поступает, тот сам себе "злобный буратино". А если уж приспичило, то передавать нужно char-овский указатель, а не long-овский и копировать побайтово. Собственно все то же самое, что делает memcpy, с которой у топикстартера все нормально работает.

Цитата(AirDevil @ Oct 20 2009, 01:27) *
В принципе и делал когда глюки были. Выравнивание с помощью memcpy и всё. Я думал, что возможно еще есть пути. Оказывается, что нет и вижу что делал правильно.
SasaVitebsk
Была аналогичная проблема.
Данные "готовились" на компе и передавались в МК. В первом релизе МК был AVR, поэтому данные были выровнены на байт. Точнее просто не выравнивались а передавались максимально упаковано.
Потом в качестве проца применил ARM7.
При приёме я их анализирую и сразу выравниваю. Так оказалось проще всего. Зато при работе, я вообще не имею головной боли.
zltigo
Цитата(SasaVitebsk @ Oct 20 2009, 12:17) *
Была аналогичная проблема.

Наиболее проходной вариант работать по указателю на нужную упакованную структуру. Если форматы подвластны, то подстроить, если нет, то ... не судьба, или изощренно под конкретику.
SasaVitebsk
Цитата(zltigo @ Oct 20 2009, 12:23) *
Наиболее проходной вариант работать по указателю на нужную упакованную структуру. Если форматы подвластны, то подстроить, если нет, то ... не судьба, или изощренно под конкретику.

Я так и делаю. Форматы подвласны. smile.gif
Я принимаю первые байты структуры (метка + имя структуры), выкидываю метку, а по имени структуры идентифицирую её. Далее диспетчером памяти выделяю под неё место и располагаю указатель на начало структуры в спец массиве указателей. При выделении места учитываю новый размер и при пересылке сразу перепаковываю. В дальнейшем работаю как с выровненной.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.