Перейти к содержанию
    

Вопрос на счет выравнивания переменных

Всем привет!

 

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.

Изменено пользователем AirDevil

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для какой архитектуры компилятор?

Вы что-то путаете.

Для начала вы определитесь какой на вашем таргете порядок байт (big/little)endian.

Поэкспериментируйте в отладчике. И всё встанет на свои места.

А отсутствие выравнивания внутри стандартных встроенных типов данных быть не может никогда!

Выравнивание есть всегда и оно зависит от разрядности таргета и от настроек компилятора и всяких там pragma pack для структур.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кто как борет это?

Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.

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

 

 

Для какой архитектуры компилятор?

ARM, например. Не AVR, не x86....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.

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

 

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

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

 

С П А С И Б О ! ! !

Изменено пользователем AirDevil

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое и самое главное не писать "говнокод" работу которого компилятор не сможет проконтролировать.

 

В чём "говнокодность" присваивания *A = 2 при условии, что A - это указатель на u32? Автор наверняка умолчал о хитром способе вызова функции - это да. А в приведённом коде не вижу никакого криминала.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

при условии, что A - это указатель на u32

Да, это указатель на u32, но не выровненный, а находящийся, например, в каком-нибудь буфере передачи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, это указатель на 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 ? Ессно изменив прагму.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Работает ли это в GCC ? Ессно изменив прагму.

Например:

typedef unsigned int u32_unalign __attribute__ ((aligned (1)));

Все-же атрибуты веселее прагм в большинстве случаев. :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для этого..

#pragma pack(push, 1)

typedef u32 u32_unalign;

#pragma pack(pop)

Например:

typedef unsigned int u32_unalign __attribute__ ((aligned (1)));

 

Даже не знаю, сметься, плакать, или спросить где Вы оба берете такую траву? Можно я помолчу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

От зараза, не сработала :biggrin:

Я обычно через структуру или 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;" внутри прагмы не работает?

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но этот вариант уже точно правильно работает...

Чем дальше в лес, тем больше дров :(. Сколько еще "идей"? Может лучше спать, а поутру почитать, что за прагма pack и для чего она годится?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чем дальше в лес, тем больше дров :(. Сколько еще "идей"? Может лучше спать, а поутру почитать, что за прагма pack и для чего она годится?

:)

Вы удивитесь, но она не только отключает выравнивание многобайтных переменных внутри структур/юнионов, но и организует побайтный (при pack(1)) доступ ко всем полям внутри структур/юнионов. Я проверил в ИАРе - при обращении к полю l например (в описанном мной юнионе) чтение и запись происходят побайтовые. Я так думаю, что автору темы именно это и надо было.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хотя вопрос к тем, кто знает - почему "typedef u32 u32_unalign;" внутри прагмы не работает?
Потому что

Pragma directive | Description

-------------------------------------------------------------------------------

pack | Specifies the alignment of structures and union members

А отдельные переменные и так всегда выровнены.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отдельные переменные не всегда выравнены. В посте у автора темы параметром передаётся ссылка на u32. Вполне "законно" можно передать туда адрес переменной u32, находящейся в структуре с невыравненными переменными. ИАР при этом выдаст варнинг, что это опасно. GCC не знаю выдаст или нет. Так вот, если бы можно было создать тип u32 с атрибутом побайтового обращения, то не пришлось бы извращаться с юнионом. Отсюда вопрос - можно ли?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вполне "законно" можно передать туда адрес переменной u32, находящейся в структуре с невыравненными переменными.
Кто так поступает, тот сам себе "злобный буратино". А если уж приспичило, то передавать нужно char-овский указатель, а не long-овский и копировать побайтово. Собственно все то же самое, что делает memcpy, с которой у топикстартера все нормально работает.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...