Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Приведение типа указателя на элемент структуры
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
_Pasha
Цитата(ViKo @ Oct 18 2012, 10:54) *
Приведение типов - не хак. А осознанная необходимость.
***
Cortex-M это позволяет делать, начиная с любого адреса.

biggrin.gif А сколько воплей у народа по поводу невыровненного доступа на AT91** например! Там не особо позволяет 7tdmi.

Цитата(ViKo @ Oct 18 2012, 11:27) *
лишнее

Оно уже для другого: читаем программу и если чего-то надо добавить, сразу видим, сколько бит осталось.
AHTOXA
Цитата(Палыч @ Oct 18 2012, 14:16) *
А теперь попробуйте проверить на такой структуре:

Да, но речь шла о структурах, уже имеющих вручную сформированные отступы, типа такой:
Код
typedef struct
{
    uint8_t a;
    uint8_t padder1;    // - отступ
    uint16_t b;
    uint16_t padder2;  // - отступ
    uint32_t c;
}str;

Такие структуры используются, в частности, в заголовочных файлах от ST для описания периферии процессоров STM32. И меня интересует вопрос, могут ли такие структуры при каких-либо условиях перестать соответствовать описываемой ими периферии.
Пока получается, что всё нормально, соответствуют при любых ключах компиляции. (Ну, кроме непонятного случая, описанного MrYuran-ом)
XVR
Цитата(ViKo @ Oct 18 2012, 12:27) *
лишнее
Да, точно. Просчитался laughing.gif
esaulenka
Цитата(Палыч @ Oct 18 2012, 10:55) *
Вставить #pragma pack(n) или указать транслятору -fpack-struct=n cо значением n отличным от 1.


Раз тут пошли "страшные истории"...
pragma pack(n) надо обязательно закрывать pragma pack()
При включении заголовка с незакрытой прагмой такие интересные косяки проявляются - все структуры в одном модуле сами собой "упаковываются", а в другом - остаются неупакованными, в зависимости от последовательности #include.

Пример для наглядности:
Код
a.h:
#pragma pack (1)

b.h
typedef struct .... b_struct;

a.c
#include "a.h"
#include "b.h"
b_struct A;

b.h
#include "b.h"
b_struct B;


Так вот, A и B получились РАЗНЫЕ, хотя этого вряд-ли кто-то добивался :-)
Короче, плохая это прагма, не ленитесь писать атрибуты для каждой структуры.
ReAl
Цитата(AHTOXA @ Oct 18 2012, 11:45) *
Пока получается, что всё нормально, соответствуют при любых ключах компиляции. (Ну, кроме непонятного случая, описанного MrYuran-ом)
Там, я так понял, ещё битовые поля были в подструктурах ioregister_t.
Что-то могло и на этом набежать.
Скажем,
Код
typedef {
    unsigned f : 1;
} flag_t;

typedef {
    flag_t a;
    flag_t b;
} flags2_t;
структура flags2_t займёт 2*sizeof(unsigned), а не один байт. Причём никакие pack не помогут.
_pv
Цитата(esaulenka @ Oct 18 2012, 19:23) *
Короче, плохая это прагма, не ленитесь писать атрибуты для каждой структуры

а если есть некая структура
Код
typedef struct{
  u8 b;
  u32 c;  
  u8 d;
  u16 a;  
} t_struct_A;


и указатель
Код
t_struct_A * p;

который еще потом может вдруг оказаться совсем невыровненным, ну там преамбула например частично потерялась:
Код
u8 buff[100500];
p = &buff[17];

в каком именно месте и какие прагмы должны стоять чтобы p->c = 0xABCD1234; нормально работало всегда и везде?
или так лучше вообще не делать, а данные просто макросами по байтам по смещениям вытаскивать чтобы ни от платформы ни от компилятора не зависеть?
AHTOXA
Цитата(ReAl @ Oct 18 2012, 20:47) *
Там, я так понял, ещё битовые поля были в подструктурах ioregister_t.
Что-то могло и на этом набежать.

Наверное.
Ну а в результате, какой будет вывод? Можно безбоязненно пользоваться структурами от ST? Или ждать, когда _Pasha сделает базу данных? sm.gif
ViKo
Цитата(AHTOXA @ Oct 18 2012, 19:20) *
Можно безбоязненно пользоваться структурами от ST?

Если программируем аппаратные средства микроконтроллеров STM32xxx, то используются не структуры, а указатели на типы структур, расположенные по фиксированным адресам.
Если просто пользуемся структурами, подобными предложенным ST, то не все ли равно, как упакованы данные? Куда записали, оттуда и прочитаем.
AHTOXA
Цитата(ViKo @ Oct 19 2012, 10:41) *
Если программируем аппаратные средства микроконтроллеров STM32xxx, то используются не структуры, а указатели на типы структур, расположенные по фиксированным адресам.

Какая нафиг разница? Если структура вдруг разъедется, то мы промахнёмся мимо нужного регистра и по указателюsm.gif
ViKo
Цитата(AHTOXA @ Oct 19 2012, 07:59) *
Какая нафиг разница? Если структура вдруг разъедется, то мы промахнёмся мимо нужного регистра и по указателюsm.gif

Как же она разъедется, если указателю передан конкретный адрес! А дыры зарезервированы неиспользуемыми переменными.
P.S. Мы же ее (структуру) уже разъехали разъездили раскатали растянули.
AHTOXA
Цитата(ViKo @ Oct 19 2012, 11:49) *
Мы же ее (структуру) уже разъехали разъездили раскатали растянули.

Так вот я и выясняю, не может ли она после этого разъехаться ещё большеsm.gif
Представьте, что есть ключ компилятора, который каждый байт в структуре выравнивает на границу слова. С таким ключом всё наше растягивание пойдёт насмарку.
_Pasha
Цитата(AHTOXA @ Oct 19 2012, 10:31) *
Так вот я и выясняю, не может ли она после этого разъехаться ещё большеsm.gif
Представьте, что есть ключ компилятора, который каждый байт в структуре выравнивает на границу слова. С таким ключом всё наше растягивание пойдёт насмарку.

Самое простое - не морочить, а заложить где-то assert, только вот что лучше проверять: небось, sizeof какой-то тестовой структуры, не обязательно прям-таки осмысленной и привязанной к реальным портам, но с использованием всех индуистских _IO32 и прочая.
ViKo
К счастью, в железе STM32 адреса устройств уже распределены так, что "упаковываются" в структурах согласно своему естественному размеру, int16_t по границам полуслова, int32_t по границам слова. Во всяком случае, я не заметил, чтобы где-то в stm32fxx.h было не так. Поэтому, если не насиловать компилятор прагмами pack(n), ничто расползаться не должно.
А __packed может только утоптать структуру, но не раздвинуть ее. А от этого мы уже защитились RESERVED.
Так, вроде?
_Pasha
Цитата(ViKo @ Oct 19 2012, 12:32) *
К счастью, в железе STM32 [...]

В принципе, тут зацепились мы за платформенно-независимый вопрос.
Цитата
Поэтому, если не насиловать компилятор прагмами pack(n)

... а также приведением типов указателей на элемент структуры sm.gif ...
=GM=
Цитата(ViKo @ Oct 17 2012, 09:51) *
Допустим, имеется структура из байтов. Хочу инициализировать сразу 2 байта 16-битовым числом, или сразу 4 байта 32-битовым числом. Привожу указатель к нужному типу

Похоже, при формировании структуры си-компилятор находит элемент с максимальной длиной и выделяет каждому элементу структуры размер памяти, равный максимальной длине. По крайней мере, для кейловского компилятора я это доказал. Выделил структуру
typedef struct
{
unsigned long VARA;
unsigned char VARB;
unsigned int VARC;
}
CRCSTRUCT;

CRCSTRUCT STRD;

и в дибаггере стал туда писать побайтно, начиная с VARА. В VARА записалось 4 байта, как и ожидалось, в VARВ записался один байт, остальные три писались в никуда и не отображались, в VARC записалось два байта, остальные записались в никуда.

Так что дырки в структурах всегда будут, если структура содержит элементы разной длины.
_Pasha
yeah.gif
Есть Грабля!
CODE
typedef struct
{
char id[2];
uint32_t size;
char reserved[4];
uint32_t offset;
uint32_t bmp_infolen;
uint32_t width;
uint32_t height;
uint16_t planes;//number of
uint16_t bits_per_pix;
uint32_t compress_type;
uint32_t picture_size;
uint32_t Hresolution;
uint32_t Vresolution;
uint32_t used_colors;
uint32_t important_colors;
} bmp_header_t;

Компилим
Код
gcc версия 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

с дефолтными настройками code::blocks (уверяю, там ничего страшного нету, выравнивание нигде принудительно не включено)
Пишет после bmp_header.id два нулевых байта, также при выводе его размера показывает 56 байт супротив 54-х.
В общем, подарок для АНТОХИ. sm.gif
ЗЫ причем, сгенеренный и исходный BMP отличаются ровно на этих 2 байта
PPS добавили #pragma pack(1) - получили всё, что надо. 54 байта.
Оттакот!
ppps Что-то пользоваться таким ГЦЦ расхотелось...
Сергей Борщ
QUOTE (_Pasha @ Nov 9 2012, 20:48) *
CODE
typedef struct
{
    char        id[2];
    uint32_t    size;
И что же вы ожидали (надеюсь, это был не AVR или MSP430)?
AHTOXA
Цитата(_Pasha @ Nov 10 2012, 00:48) *
yeah.gif
Есть Грабля!

Да вроде не особо, uint32_t выровняли на 4 байта. Не вижу криминалаsm.gif
_Pasha
Цитата(AHTOXA @ Nov 9 2012, 22:33) *
Да вроде не особо, uint32_t выровняли на 4 байта. Не вижу криминалаsm.gif

Разобрался... чего-то вбил себе в голову, что uint16_t там не подряд идут. И непонятно, чего там так, там эдак. Тогда всё правильно.
ViKo
Всплыл вопрос, кажется, подойдет в эту тему.
Создаю суперструктуру из нескольких разных структур. В каждой из структур переменные разного размера кидаю, как попало. Не знаю, создаются дыры или нет, но пока использовал структуры по-отдельности, проблем не было. Keil знает, куда положил, и откуда брать. Для Cortex-M нет проблем. В суперструктуре должно быть аналогично.

Теперь хочу копировать суперструктуру в другую, такую же (backup). Хочу делать это 32-битовыми пересылками. Кроме того, хочу вычислять аппаратно CRC суперструктуры, туда тоже нужно посылать 32-битовые слова.
Задаю указателю на uint32 адрес суперструктуры (uint32_t *)&Ctrl. Вычисляю ее размер в словах (!) size(Ctrl_t) / 4. И так собираюсь использовать.

Вопросы:
1. Что гарантирует, что вся суперструктура разместится по выровненному до слова адресу? Что будет, если первый элемент - 8-битовый?
2. Как задать, чтобы ее размер был равен целому числу слов? Пока напихал несколько пустых байтов, каждая мелкая структура - по 2-4-8 байтов, общее количество 44 байта (но, может, есть и дыры двухбайтовые?). В конце суперструктуры задаю 32-битовую CRC, это гарантирует выравнивание по словам, и целое число слов?
MrYuran
Цитата(ViKo @ Dec 20 2013, 13:45) *
1. Что гарантирует, что вся суперструктура разместится по выровненному до слова адресу? Что будет, если первый элемент - 8-битовый?

Если явно определено выравнивание (pack или aligned), то вроде как должно.
ViKo
Почитал здесь - http://www.keil.com/support/man/docs/armcc...he.htm#Cihbbgii
Похоже, ничего делать не надо.

Цитата(MrYuran @ Dec 20 2013, 13:35) *
Если явно определено выравнивание (pack или aligned), то вроде как должно.

Похоже, лучше, наоборот, ничего не задавать. Тогда само разместится ровненько.
ig_z
QUOTE (ViKo @ Dec 20 2013, 11:45) *
2. Как задать, чтобы ее размер был равен целому числу слов?


Я точно не вспомню, но делал что то типа такого:
Помещал "супер структуру" + массив байт в "супер-супер структуру"
Размерность массива байт задавал как остаток от деления sizeof("супер структура") на 4.
Единственное, что не могу вспомнить, как обходил ситуацию с нулевым размером массива байт.
ViKo
Запустил компиляцию с опцией --remarks.
Вижу:
enum занимают по 32 бита! Неоправданная роскошь.
К структуре с enum и 3-мя uint_16 добавилось... видимо 2 байта в конце.
По структуре Ctrl никаких замечаний не увидел.

Добавил uint8_t в конец Ctrl. Получил замечание, что добавило padding.
Делаю вывод - ничего не бойся, не проси... rolleyes.gif Сам Кейл придет и принесет.
PheeL
Цитата(ViKo @ Dec 20 2013, 15:08) *
enum занимают по 32 бита! Неоправданная роскошь.

Каждый из элементов enum - это int. Так что если машинное слово 32-х разрядное, то всё верно.
ViKo
Цитата(PheeL @ Dec 20 2013, 14:14) *
Каждый из элементов enum - это int. Так что если машинное слово 32-х разрядное, то всё верно.

Да, верно. Просто я об этом не задумывался. Да оно и нашлось всего в одном месте. Там и не сам enum стоял, а производный тип - typedef enum {...} ... Заменю на uint16_t и сэкономлю 4 байта!

Что любопытно. Имею в структуре 2 байта, в первом - битовые поля, во втором - uint8_t (вообще, reserv, для выше сказанного выравнивания). Так вот, такую 2-байтовую структуру Keil размещает в суперструктуре, не выравнивая по 2-байтовой границе. Как и написано по вышеприведенной ссылке, структура выравнивается по границе ее наибольшего члена.
XVR
Цитата(ViKo @ Dec 20 2013, 13:45) *
1. Что гарантирует, что вся суперструктура разместится по выровненному до слова адресу?
Компилятор гарантирует, что любое поле структуры (в том числе и поля вложенных структур) будет выровнено на его размер. Так же гарантируется, что это будет так и для массива структур. Отсюда автоматически следует, что сама структура всегда будет выровнена по ее полю с максимальным размером, и размер структуры тоже будет кратен размеру этого поля.
Цитата
Что будет, если первый элемент - 8-битовый?
Не важно, какой первый. Главное, что бы внутри был хотя бы один int
Цитата
В конце суперструктуры задаю 32-битовую CRC, это гарантирует выравнивание по словам, и целое число слов?
Да
Сергей Борщ
Цитата(ViKo @ Dec 20 2013, 11:45) *
В конце суперструктуры задаю 32-битовую CRC, это гарантирует выравнивание по словам, и целое число слов?
Как уже было сказано - да, гарантирует. Но все "дырки", оставшиеся от выравнивания полей, могут быть заполнены совершенно произвольным мусором. Учтите это при расчете CRC. Т.е. либо перед заполнением полей структуры обнуляйте выделенную под нее память при помощи memset, либо считайте CRC конкретных полей, а не всей памяти струткуры, либо размещайте поля так, чтобы не между ними не образовывалось "дырок".
AHTOXA
Цитата(Сергей Борщ @ Dec 24 2013, 22:06) *
Но все "дырки", оставшиеся от выравнивания полей, могут быть заполнены совершенно произвольным мусором. Учтите это при расчете CRC.

Да, как-то я напоролся на такое. Была структура, в конце структуры crc16. При инициализации проверялось crc, и, в случае несовпадения, значениям структуры присваивались значения по умолчанию.
Всё это прекрасно работало, до тех пор, пока я не поменял размер одного члена структуры с uint8_t на uint16_t. После этой замены моя программа стала дурить. Оказалось, что при смене размера члена общий размер структуры не изменился, crc16 тоже совпал. А вот значение этого члена получилось недопустимо большое (за счёт добавленного байта).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.