Обсуждаем контроллеры компании Atmel.
Ответить

структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 08:53:27

день добрый!

краткое описание задачи:

1. есть некая структура, с несколькими полями (пока они одного типа, но, для общего решения, пусть они будут разнотипные)

2. нужно со всеми полями структуры провести однотипные и, возможно рекурсивные, задачи ("рекурсия_по_полю"), для простоты опишем эту задачу так:
- нам прислали ящик яблок
- ого! но мы можем съесть за раз только одно
- отправляем сами себе же посылку с одним яблоком
- ого! нам прислали ящик с одним яблоком, наш размерчик, лопаем, благодарим отправителя, требуем продолжения банкета!
- и так, пока не сожрем всю посылку

(конкретика для этой задачи не важна, тема топика дальше)

3. подобные задачи нужно будет сделать со всеми полями структуры по порядку
4. т.к. задачи "однотипные", то вполне логична "рекурсия_по_структуре"
5. можно решить тупо в лоб, написать кучу функций, реализующих обработку каждого поля, и вызывать весь этот паровоз последовательно, один за другим...

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

т.е. реализовать обработку в одной функции, а к полям обращаться по индексу

далее код, который последовательно приближается к такому решению, но на последнем этапе осталась нерешенная задача по использованию типа в разыменовании, нужно подставлять разные типы.

Код:
p_void = ( ((void*)p_void) + shift ); *( (uint8_t  *)p_void) = ((i+1)*10);  // i-й элемент

вот тут
Код:
(uint8_t  *)p_void)


я так понимаю, "массив_типов" создать не получиться :о)

ну... кидайтесь помидорами, идеями, мымслями

спасибо

Код:
avr-gcc, С-only, linux, etc...


Код:
#include <util/delay.h>

#include "main.h"
#include "lib/prn.h"    // prn-lib()

#define SIZE_STRUCT   3
#define SIZE_8        1 // (sizeof int8_t ) // не нашел набегом...
#define SIZE_16       2 // (sizeof int16_t)
#define SIZE_32       4 // (sizeof int32_t)

uint8_t size[SIZE_STRUCT] = {SIZE_8, SIZE_16, SIZE_32};

typedef struct
{
uint8_t  a;
uint16_t b;
uint32_t c;
} t;

typedef t* p;

t test  ; // экземпляр структуры
p p_test; // указатель на структуру

////////////////////////////////////////////////////////////////////////////////
void prn_struct(int8_t i)
////////////////////////////////////////////////////////////////////////////////
{
prn("--- %i \n", i);
prn("test.a = %u \n", test.a);
prn("test.b = %u \n", test.b);
prn("test.c = %lu\n", test.c);
}
////////////////////////////////////////////////////////////////////////////////
int main(void)
////////////////////////////////////////////////////////////////////////////////
{
void* p_void;
prn_init();
prn("### struct ###\n");

p_test = &test;

p_test->a = 1;
p_test->b = 2;
p_test->c = 3;
prn_struct(1);


/*/
// var.1 доступ к "одношерстным" данным
//
*(((uint8_t*)p_test) + 0) = 4;
*(((uint8_t*)p_test) + 1) = 5;
*(((uint8_t*)p_test) + 2) = 6;
prn_struct(2); //*/

//
// var.2 доступ к "разношерстным" данным
//
*( (uint8_t *) (((void*)p_test)                                     ) ) = 4; // 1й элемент
*( (uint16_t*) (((void*)p_test) + sizeof(uint8_t)                   ) ) = 5; // 2й элемент
*( (uint32_t*) (((void*)p_test) + sizeof(uint8_t) + sizeof(uint16_t)) ) = 6; // 3й элемент
prn_struct(3); //*/

//
// var.3 доступ к "разношерстным" данным
//
p_void = (((void*)p_test));

p_void = (((void*)p_void)                   ); *( (uint8_t  *)p_void) = 7;  // 1й элемент
p_void = (((void*)p_void) + sizeof(uint8_t )); *( (uint16_t *)p_void) = 8;  // 2й элемент
p_void = (((void*)p_void) + sizeof(uint16_t)); *( (uint32_t *)p_void) = 9;  // 3й элемент
prn_struct(4); //*/

//
// var.4 доступ к "разношерстным" данным через индекс
//
int8_t i, shift;
p_void = (((void*)p_test));

for(i=0; i<3; i++)
  {
  if(i<=0) { shift = 0        ; } // реализация сдвига
  else     { shift = size[i-1]; }

  p_void = ( ((void*)p_void) + shift ); *( (uint8_t  *)p_void) = ((i+1)*10);  // i-й элемент
  }
prn_struct(5); //*/

return 0;
}
////////////////////////////////////////////////////////////////////////////////



для "одношерстных" данных можно упростить
Код:
for(i=0; i<3; i++)
  {
  *( (uint8_t*) (((void*)p_test) + i) ) = ((i+1)*10+6); // i-й элемент
  }
Последний раз редактировалось sunjob Пт фев 12, 2021 18:13:51, всего редактировалось 2 раз(а).

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 10:04:04

Я правильно понимаю - хочется одинаково "пройтись" по всей структуре, содержащей разные типы? Ес-но придется в обработчике вручную учитывать типы. На Си. На C++14 пишут можно шаблонами решить органично: https://github.com/CppCon/CppCon2016/bl ... 202016.pdf

На чистом Си для упрощения задачи, чтобы не писать эту кучу разношерстных кастов, можно данные одного типа группировать в массивы внутри структуры. "5 яблок uint8_t, 3 яблока uint16_t и 2 яблока uint32_t".

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 10:41:20

1. на СИ
2. стуктура внешняя, без изменений (и задача пока решается в общем случае! последний код - есть решение для случая с одношерстыми данными)
3. судя по предложенному коду
Код:
"5 яблок uint8_t, 3 яблока uint16_t и 2 яблока uint32_t".

задачу не совсем поняли... :))

попробую обьяснить еще раз

1. имеется N полей
2. каждое поле должно "обсчитаться"
3. приходит посылка с "большим количеством яблок" для каждого поля (внешний цикл), (т.е. куча посылок, 1я посылка для поля 1, 2я посылка для поля 2, 3я посылка...)
4. для каждого поля посылка разбивается на посылки с одним яблоком, и вызывает рекурсия "самому себе"
5. и так "разбор" посылок для каждого поля

...

так-то, текущая задача достаточно проста, с одним типом данных и, поэтому, внешний цикл вызовов уже реализован (тот самый последний код)

просто, для тренировки усов, лап и хвостов... решил потренироваться "на разношерстных котах" :)))

ну ... т.е. пока не вижу решения :)) ... или уточните ваши идеи

спасибо

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 12:03:00

Давайте без яблок. Я выше написал - "Я правильно понимаю - хочется одинаково "пройтись" по всей структуре, содержащей разные типы?" - это так? Если так, то ответ там уже был дан. На чистом Си невозможно пройтись итеративно по всей структуре с разными типами данных, не описывая в коде логику работы с этими типами данных. Т.е. как бы универсально написать так, что скажем к каждому элементу структуры прибавлялось бы 1, внезависимости от размерности и типов данных структуры - не получится. Логика кода ("внешний цикл") должен знать, с чем он работает.
Как альтернативу, для упрощения написания этой логики, я предложил группировать данные в структуре по типам.

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 12:47:14

в GCC есть макрос offsetof, который позволяет обратиться к полю структуре по смещению этого поля, зная начало структуры. т.е. не по имени поля обращаться, а по его относительному адресу в памяти. таким образом, можно в функцию передавать значение этого макроса и внутри функции абсолютно однотипно обсчитывать любые поля.

я верно понял, что вы хотите?

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 12, 2021 13:00:54

to NStorm
внезависимости от размерности и типов данных структуры - не получится

-> если опустить некоторые моменты :)) не совсем красиво, но все в одном месте, уже и это плюс :wink:
Код:
...
// var.4 доступ к "разношерстным" данным через индекс
...
switch(i)
  {
  case   0 : p_void = ( ((void*)p_void) + shift ); *( (uint8_t  *)p_void) = ((i+1)*10); break;
  case   1 : p_void = ( ((void*)p_void) + shift ); *( (uint16_t  *)p_void) = ((i+1)*10); break;
  case   2 : p_void = ( ((void*)p_void) + shift ); *( (uint32_t  *)p_void) = ((i+1)*10); break;
  }



...

to ARV
...обратиться к полю структуре по смещению этого поля, зная начало структуры. т.е. не по имени поля обращаться, а по его относительному адресу в памяти...

так и сделано

в GCC есть макрос offsetof + таким образом, можно в функцию передавать значение этого макроса и внутри функции абсолютно однотипно обсчитывать любые поля.

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

внутри функции абсолютно однотипно обсчитывать любые поля

с макросом еще не разбирался, с помощью него обращение к полям через индекс?

...

Offset

6.53 Support for offsetof

GCC implements for both C and C++ a syntactic extension to implement the offsetof macro.

Код:
primary:
        "__builtin_offsetof" "(" typename "," offsetof_member_designator ")"

offsetof_member_designator:
          identifier
        | offsetof_member_designator "." identifier
        | offsetof_member_designator "[" expr "]"

This extension is sufficient such that

Код:
#define offsetof(type, member)  __builtin_offsetof (type, member)


is a suitable definition of the offsetof macro. In C++, type may be dependent. In either case, member may consist of a single identifier, or a sequence of member accesses and array references.

...

гм.. эге... мур... не, бля, точно муррр...
я столько не выкурю :)))
придется почитать, что пишут по этому поводу бывалые коты и фугля... мугля ... гугля... да, точно гугля!

зы: спасибо

Re: структуры, доступ к "разношерстным" данным через индекс

Сб фев 13, 2021 06:32:32

Какая то нереальная задача. Каждая структура обрабатывается соответственно. Хоть полями, хоть кусочками байтами. Универсальности нет. И не выдумывайте лишнего.

Re: структуры, доступ к "разношерстным" данным через индекс

Сб фев 13, 2021 08:00:49

на изилектрониксе предложили хитрый ход конскими ушами :)))

я так понимаю, "массив_типов" создать не получиться :о)

->
Код:
struct types{
uint8_t _t0;
uint16_t _t1;
uint32_t _t2;
};

#define TYPE(n) typeof(types._t##n)


срочно надо попробовать :write:

...

ну а пока очевидный педальный способ (причесал код из топика...:o)))
Код:
//
// var.4 через индекс / switch (mod)
//
p_void = (((void*)p_test));

for(i=0; i<3; i++)
  {
  switch(i) // выбор, по "соответствующему типу"
    {
    case   0 : *( (uint8_t  *)p_void) = (256-1       ); break;
    case   1 : *( (uint16_t *)p_void) = (65536-1     ); break;
    case   2 : *( (uint32_t *)p_void) = (4294967296-1); break;
    }

  p_void = ( ((void*)p_void) + size[i] ); // сдвиг указателя "с опозданием" (то, что нужно :о)
  }

prn_struct(4); //*/

Re: структуры, доступ к "разношерстным" данным через индекс

Сб фев 13, 2021 12:14:13

Ничего нового не увидел. И вы только что своими руками доказали, универсальности нет. Свитч кейс, кстати, первое, что мне в голову пришло. Сам так делал неоднократно. Но с индексом не заморачивался. Выхлоп больше получается.

Re: структуры, доступ к "разношерстным" данным через индекс

Сб фев 13, 2021 17:28:56

Ничего нового не увидел

калейдоскоп купите! :)))

...

ВСЕМ, кто по делу, ОГРОМНОЕ СПАСИБО!

пока непонимание по поводу "подсказки"
Код:
#define TYPE(n) ...

Re: структуры, доступ к "разношерстным" данным через индекс

Вс фев 14, 2021 12:06:01

все универсальные решения на поверку оказываютс во-первых, не универсальными, а во-вторых, громоздкими.
что касается доступа к полям структуры по индексу, т.е. по номеру поля, то напрашивается следующее универсальное решение
1. обращаться будем при помощи "универсальной" функции
Код:
void something(const field id, void *rec, rec_type *rectype){
   int32_t field; // сюда поместим значение поля
   field = rectype[id].func(rec + rectype[id].offset);
   // дальше делаем с этим field то, что нужно
}

первый параметр - номер поля, второй - адрес структуры, третий - адрес массива, в котором описаны поля этой структуры
2. поля структуры описываются так:
Код:
typedef int32_t (value*)(void*); // тип описания функции, возвращающей значение поля
typedef struct{
  uint8_t offset; // смещение пол относительно начала структуры
  value func; // функция, которая вернет значение поля
} rec_type;

3. создаем функции для полей разных типов. и тут первая проблема "универсальности" - только целочисленные значения могут быть возвращены. float, например, уже не укладывается в концепцию.
Код:
int32_t get_byte(char *ptr){
  return *ptr;
}

int32_t get_int(int *ptr){
  return *ptr;
}
// и так далее для всех вариантов полей, которые могут быть приведены к целочисленному значению

4. создаем и инициализируем массивы описаний разных структур, делая такми способом заготовки для обращения по индексу.
5. ну, а далее - обращаемся к полям по индексам...

все это давным давно реализовано в С++, т.к. по сути является именно сишной реализацией подобия таблиц виртуальных методов... но всё это хуже, чем С++, поскольку - см. выше, - имеет ограничения по "универсальности". и, как видите, реализация тоже не очень краткая и не очень удобная - см. начало моего поста - вторая проблема "универсальности".

мой опыт программирования позволяет мне утверждать, что выход тут только один - отказаться от НЕНУЖНОЙ универсальности, т.е. переформулировать задание и/или алгоритм так, чтобы необходимости в такой "универсальности" не возникало.

Re: структуры, доступ к "разношерстным" данным через индекс

Пт фев 26, 2021 21:25:15

- нам прислали ящик яблок
- ого! но мы можем съесть за раз только одно
- отправляем сами себе же посылку с одним яблоком
- ого! нам прислали ящик с одним яблоком, наш размерчик, лопаем, благодарим отправителя, требуем продолжения банкета!
- и так, пока не сожрем всю посылку

Думал не подвернется случай... :)
Apple.jpg
(23.4 KiB) Скачиваний: 120

Re: структуры, доступ к "разношерстным" данным через индекс

Сб фев 27, 2021 15:18:34

да...но там задачка-то еще упрощённо описана... есть еще и "морды", которые будут жрать эти яблоки... :о)

Re: структуры, доступ к "разношерстным" данным через индекс

Чт мар 18, 2021 20:59:21

с макросом еще не разбирался, с помощью него обращение к полям через индекс?


Непонятно, зачем вы заостряете внимание на каком-то "обращении через индекс". Обращение через индекс, то есть определение положения очередного поля в памяти, никакого труда не представляет и легко реализуется через таблицу смещений с помощью того же `offsetof` (которое есть не "в GCC", как тут сбивающе с толку написали, а является хрестоматийной классикой стандартного языка С, то есть к GCC как таковому не имеет никакого отношения вообще).

Проблема то не в "обращении по индексу". Проблема в том, что каждое поле может иметь свой тип и требовать своей собственной обработки. Тут, очевидно, можно выкрутиться через таблицу обработчиков, принимающих `void *` и уже внутри знающих, что делать со своими полями и какой тип они имеют.

Re: структуры, доступ к "разношерстным" данным через индекс

Вс апр 18, 2021 06:26:03

... Тут, очевидно, можно выкрутиться через таблицу обработчиков, принимающих `void *` и уже внутри знающих, что делать со своими полями и какой тип они имеют...


так и сделано, только проще и нагляднее :)))
Ответить