|
Union c внешними (external) переменными, подскажите, как сделать |
|
|
|
Apr 14 2010, 12:09
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 4-04-07
Пользователь №: 26 770

|
Здравствуйте. Кратко опишу проблему: В программе есть два модуля: один низкоуровневый - "lowlevel.c" и основной модуль "main.c". В модуле "lowlevel.c" объявлен некий буфер Код char buffer[10]; и модуль умеет с ним работать, например, посылать данные из этого буфера на внешнее устройство. Этому модулю нет дела до того, что означает каждый байт этого буфера, его дело - передать данные. На самом деле каждый байт из этого буфера имеет особый смысл: заголовок, управляющие поля, данные, контрольная сумма. Хочется, чтобы основной модуль мог работать с этим буфером как со структурой, т.е. что-то вроде того: Код union { char buffer[10]; struct { char NT; char mask; char event; char blok; char echo; char data[3]; int crc; }; } LO_TRBuf; Однако, всё осложняется тем, что элементы структуры описаны с модуле "main.c", а буфер находится в "lowlevel.c". Пробовал использовать директиву "extern" в разных местах, но добиться желаемого не удалось. Можно, конечно перенести описание структуры в "lowlevel.h", но это будет неправильно с точки зрения инкапсуляции данных. Посоветуйте какое-либо решение?
|
|
|
|
|
Apr 14 2010, 12:15
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Dmitro25 @ Apr 14 2010, 16:24)  Однако, всё осложняется тем, что элементы структуры описаны с модуле "main.c", а буфер находится в "lowlevel.c". А нельзя структуру описать в main.h? И вставляйте потом куда угодно extern-ом вы даёте ссылку на экземпляр объекта, а не на его описание
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Apr 14 2010, 12:18
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 4-04-07
Пользователь №: 26 770

|
2MrYuran: Она у меня и так описана в main.c. А подключать к lowlevel.c модуль main.c не вижу смысла - зачем ему данные более высокого уровня?
|
|
|
|
|
Apr 14 2010, 12:30
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Работать с указателями. Код typedef struct { char NT; char mask; char event; char blok; char echo; char data[3]; int crc; } mystruct; extern char *buffer; void test() { mystruct *pData = (mystruct *)buffer; pData->NT = 12; pData->echo = 'A'; } Если процессор требует выровненного доступа (ARM, MSP) - при объявлении структуры указать, что структура упакована - #pragma pack, __attribute__((packed))
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 14 2010, 12:46
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 4-04-07
Пользователь №: 26 770

|
2Сергей БорщСпасибо за ответ. Я уже думал о таком решении. Но при таком способе снижается производительность и возрастает объём кода, поскольку при статическом размещении переменных компилятор мог ещё на этапе компиляции вычислить адрес члена структуры, а теперь каждый раз он будет вычислять место расположения переменной в памяти, прибавляя смещение к базовому адресу. И вроде бы ничего фантастического я не хочу. Просто нужно, чтобы в модуле создался union с данными, объявленными в другом модуле, но как-то не получается. Если пишу Код union { extern char buffer[10]; struct { char NT; ... то компилятор выдаёт "a storage class may not be specified here".
|
|
|
|
|
Apr 14 2010, 13:06
|
Частый гость
 
Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680

|
Или так: разместить объект структуры(не массив) в lowlevel и через экстерн иметь к нему доступ из main. А юзать сами данные в lowlevel уже как душе угодно. Типа того Код //lowlevel.c struct mystruct name; static uint8_t* buffer = (uint8_t*)&name; и не забывать про sizeof(mystruct), во избежании.
|
|
|
|
|
Apr 14 2010, 13:11
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Dmitro25 @ Apr 14 2010, 15:01)  Но при таком способе снижается производительность и возрастает объём кода, поскольку при статическом размещении переменных компилятор мог ещё на этапе компиляции вычислить адрес члена структуры Например, адрес будет 32бит и на каждый элемент структуры в памяти будет еще храниться 4 байта адреса - вот уже "экономия"  памяти налицо. Цитата , а теперь каждый раз он будет вычислять место расположения переменной в памяти, прибавляя смещение к базовому адресу. Ага, именно так - поместит в регистр базовый адрес и будет быстренько добавлять смещение хранящееся в теле команды. Вместо того, что-бы для типа "экономии"  уже производительности грузить из памяти данных в этот-же регистр по 32bit значения. Как Вам такая трактовка? Цитата(Dmitro25 @ Apr 14 2010, 15:01)  то компилятор выдаёт "a storage class may not be specified here". Ну так пойдите ему на встречу. Опишите структуру отдельно.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 14 2010, 13:52
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 4-04-07
Пользователь №: 26 770

|
2Палыч 2baralgin Я просто для инкапсуляции хотел, чтобы модуль lowlevel ничего не знал об интерпретации полей своего буфера. Ему для работы это не нужно, достаточно знать начало буфера и его размер. Если завтра будет создан другой проект с новым протоколом, то модуль lowlevel можно будет без изменений перенести в новый проект. Переписан будет только модуль main. А с такими перекрёстными ссылками получается, что "все знают понемножку обо всех". На мой взгляд это неправильно.
2zltigo Я забыл упомянуть, что пишу для AVR, компилятор IAR, а насчёт выровненности структур, если понадобится в будущем, можно по совету "Сергей Борщ" использовать упакованные структуры. Что касается кода, который генерируется компилятором, я уже наблюдал, что компилятор, когда это ему выгодно, генерирует инструкции с индексной адресацией, а в других случаях - используется прямую адресацию. Использование же только указателей лишает его второй возможности.
Сообщение отредактировал Dmitro25 - Apr 14 2010, 13:53
|
|
|
|
|
Apr 14 2010, 14:09
|
Частый гость
 
Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680

|
Dmitro25 Пишем в lowlevel функцию типа "void* getBuffer(void)", в main полученный указатель кастуем в структуру и используем. Чтобы не было оверхеда заводим статический указатель на структуру, которую инициализируем после входа в main. А далее в программе уже используем этот указатель. ps: всё равно это всё неправильно и небезопасно, особенно вкупе с такими умными словами как "инкапсуляция"  , имхо конечно.
Сообщение отредактировал baralgin - Apr 14 2010, 14:10
|
|
|
|
|
Apr 14 2010, 20:10
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Dmitro25 @ Apr 14 2010, 15:01)  Но при таком способе снижается производительность и возрастает объём кода, поскольку при статическом размещении переменных компилятор мог ещё на этапе компиляции вычислить адрес члена структуры, а теперь каждый раз он будет вычислять место расположения переменной в памяти, прибавляя смещение к базовому адресу. За все надо платить. Можете подойти с другой стороны: Код extern void send(void * buffer, uint_fast8_t size); void test() { mystruct Data; Data.NT = 12; Data.echo = 'A'; send(&Data, sizeof(Data)); } Код extern void send_driver(void * buffer, uint_fast8_t size); #define send(object) send_driver(&object, sizeof(object)) void test() { mystruct Data; Data.NT = 12; Data.echo = 'A'; send(Data); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 15 2010, 05:56
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 4-04-07
Пользователь №: 26 770

|
2baralgin2Сергей БорщСпасибо, я, наверное, что-то подобное и сделаю, если по-нормальному не получается. Только я, скорее, склоняюсь к тому, чтобы в самом начале программы из "main" вызвать функцию Код char lowlevel_init(char *buffer, char size) которая, помимо других действий по инициализации модуля, запомнит адрес и размер буфера. 2ПалычВ случае со множеством директив #define потом трудновато менять адреса при изменении структуры.
Сообщение отредактировал Dmitro25 - Apr 15 2010, 05:57
|
|
|
|
|
Apr 15 2010, 09:37
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата(Сергей Борщ @ Apr 14 2010, 16:45)  Работать с указателями. Код typedef struct { char NT; ... int crc; } mystruct; extern char *buffer; void test() { mystruct *pData = (mystruct *)buffer; pData->NT = 12; pData->echo = 'A'; } Тут ошибка - должно быть extern char buffer[];А если сделать так - Код typedef struct { char NT; ... int crc; } mystruct; extern char buffer[]; #define pData ((mystruct*)buffer) void test() { pData->NT = 12; pData->echo = 'A'; } то и лишних поинтеров и сложений скорее всего не будет (если компилятор достаточно умный)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|