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

WinAVR(Ну или C) + Массивы в структуре

При таком определении компилятор ругается:

typedef struct {  
    const char  Engl[];
    const char  Russ[];
} LangStruct PROGMEM;

 

Мол переменной длинны, массив не в конце.

 

Собственно вопрос, а возможно ли вообще в С размещать таким образом два массива?

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


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

При таком определении компилятор ругается:

typedef struct {  
    const char  Engl[];
    const char  Russ[];
} LangStruct PROGMEM;

 

Мол переменной длинны, массив не в конце.

 

Собственно вопрос, а возможно ли вообще в С размещать таким образом два массива?

Нет конечно! Ни один, ни два и не десять массивов (в структуре или нет) так определять нельзя. И компилятор ругается справедливо, ибо размеры массивов не заданы, соответственно, компилятор не знает, сколько памяти надо для размещения переменной такого типа.

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


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

Нет конечно! Ни один, ни два и не десять массивов (в структуре или нет) так определять нельзя. И компилятор ругается справедливо, ибо размеры массивов не заданы, соответственно, компилятор не знает, сколько памяти надо для размещения переменной такого типа.

 

Почему это ни одного?

 

typedef struct {
    void       *Next;
    void       *Previous;
    void       *Parent;
    void       *Sibling;
    FuncPtr     SelectFunc;
    FuncPtr     EnterFunc;
    const char  Text[];
} Menu_Item PROGMEM;

 

Прекрасно компилится и работает. (Это из MicroMenu взято). Проблема именно в двух таких массивах.

 

Да, и к тому же опеределение типа

extern char mass[]; тоже вполне работает, но это уже отдельный разговор...

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

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


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

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

 

typedef struct {  
    const char  *pEngl; /* указатель на массив Engl */
    const char  pRuss; /* указатель на массив Russ */

} LangStruct PROGMEM;

А далее в конструкторе (функции инициализации) указателям присваивать конкретные адреса массивов... Еще бы я добавил, в таком случае, в структуру размеры массивов.

 

 

 

 

Почему это ни одного?

 

typedef struct {
    void       *Next;
    void       *Previous;
    void       *Parent;
    void       *Sibling;
    FuncPtr     SelectFunc;
    FuncPtr     EnterFunc;
    const char  Text[];
} Menu_Item PROGMEM;

 

Прекрасно компилится и работает. (Это из MicroMenu взято). Проблема именно в двух таких массивах.

 

Да, и к тому же опеределение типа

extern char mass[]; тоже вполне работает, но это уже отдельный разговор...

Интересно, а какой размер массива Text??? Зеро байт? :) Или миллион?

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


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

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

 

typedef struct {  
    const char  *pEngl; /* указатель на массив Engl */
    const char  pRuss; /* указатель на массив Russ */

} LangStruct PROGMEM;

А далее в конструкторе (функции инициализации) указателям присваивать конкретные адреса массивов... Еще бы я добавил, в таком случае, в структуру размеры массивов.

Ну да, видимо так и сделаю.

 

Интересно, а какой размер массива Text??? Зеро байт? :) Или миллион?

 

А ни какой, это примерно аналогично extern char Mass[], то есть происходит определение, а память выделяется при создании экземпляра.

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


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

А ни какой, это примерно аналогично extern char Mass[], то есть происходит определение, а память выделяется при создании экземпляра.
ИМХО это очччень не хорошо, если это на самом деле работает. Ни когда не известно, какого размера структура :07:

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


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

В определении типа не нужно указывать атрибутов (PROGMEM), они указываются при обьявлении переменных этого типа :

typedef struct {  
    const char  Engl[size1];
    const char  Russ[size2];
} LangStruct;

LangStruct PROGMEM str1;
LangStruct EEPROM str2;

 

в данном случае str1 будет размещена в программной памяти, str2 - в eeprom. size1, size2 должны быть определены перед обьявлением типа...

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

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


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

ИМХО это очччень не хорошо, если это на самом деле работает. Ни когда не известно, какого размера структура

 

Ну почему не известно, длинна всех типов в структуре, плюс длинна массива, полученная при инициализации, так получается. Кстати именно поэтому видимо и требование такое, что бы массив был в конце структуры, вот два и не получится разместить :crying: .

 

В определении типа не нужно указывать атрибутов (PROGMEM), они указываются при обьявлении переменных этого типа :

 

Ну почему же не нужно, смотря для чего, в данном случае надо что бы всё было во флеш, зачем же тогда по сто раз PROGMEM писать. :)

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

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


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

Ну почему не известно, длинна всех типов в структуре, плюс длинна массива, полученная при инициализации, так получается. Кстати именно поэтому видимо и требование такое, что бы массив был в конце структуры, вот два и не получится разместить :crying: .
Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но как, допустим, определить массив Ваших структур??? И как, допустим, в цикле их перебирать если все структуры разной длины???

 

Кстати, можете показать код инициализации члена Text[] структуры Menu_Item? Что то у меня не получилось :)

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


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

И как, допустим, в цикле их перебирать если все структуры разной длины???

 

Да, с перебором в цикле - проблема :) . Но как Вы могли догадаться, в массиве Text[] храниться текст :) , и вообщем-то данный приём только для текста-то и полезен, ибо в цикле чаще всего стоит условие while ( '\0' != Text[i++]) то есть перебираем весь массив, допустим для печати.

 

Ну а в плане инициализации то:

 

typedef struct {
    void       *Next;
    void       *Previous;
    void       *Parent;
    void       *Sibling;
    FuncPtr     SelectFunc;
    FuncPtr     EnterFunc;
    const char  Text[];
} Menu_Item PROGMEM;

Menu_Item MyStruct = {(void*)&SomePtr, (void*)&SomePtr, (void*)&SomePtr, (void*)&SomePtr, (FuncPtr)SomeFnc, (FuncPtr)SomeFnc, { "SomeTEXT" }};

 

Ну а полный код взят собственно здесь:

http://electronix.ru/forum/index.php?act=A...st&id=10450

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


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

Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но

Обычно в таких случаях либо концевой массив содержит нечто "самоограниченное" (null-terminated string, массив указателей с NULL как ограничителем), либо его размер находится в самой структуре. Например, эта структура - заготовка для кольцевого буфера, делаем malloc( sizeof(этой_структуры) + buffer_len) и присваиваем нужному полю buffer_len.

 

как, допустим, определить массив Ваших структур??? И как, допустим, в цикле их перебирать если все структуры разной длины???

А никак. Массив [] - это incomplete array, структура с ним в конце - incomplete type, по стандарту из них массивы не собираются. Естественно, массивы из указателей на них - запросто и в цикле перебирается :-)

 

Кстати, можете показать код инициализации члена Text[] структуры Menu_Item? Что то у меня не получилось :)

Без проблем.

typedef struct {
    int i;
    char c[];
} s;

s s1 = { 1, "abc" };
s s2 = { 1, "qwerty" };

struct {
    int i;
    int ii[];
} ss = { 1, {1, 2, 3} };

avr-gcc -S

	.file	"f.c"
.arch avr2
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
.global __do_copy_data
.global __do_clear_bss
.global	s1
.data
.type	s1, @object
.size	s1, 2
s1:
.word	1
.string	"abc"
.global	s2
.type	s2, @object
.size	s2, 2
s2:
.word	1
.string	"qwerty"
.global	ss
.type	ss, @object
.size	ss, 2
ss:
.word	1
.word	1
.word	2
.word	3
/* File "f.c": code    0 = 0x0000 (   0), prologues   0, epilogues   0 */

 

Кстати, до введения этого в стандарт выкручивались, задавая размер 1. В некоторых компиляторах можно было задать 0, чтобы sizeof от типа не включал сам массив, т.е. чтобы в malloc можно было писать не неестественное

malloc( sizeof(ring_buf_t) + buf_size - 1); // один элемент есть в структуре

а нормальное

malloc( sizeof(ring_buf_t) + buf_size);

 

 

 

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

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


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

typedef struct {

int i;

char c[];

} s;

 

s s1 = { 1, "abc" };

s s2 = { 1, "qwerty" };

В IAR (по крайней мере в версии 4.10, что у меня) это не работает.

 

 

 

И ИМХО - это правильно (что не работает :) ).

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


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

И ИМХО - это правильно (что не работает :) ).

И не может работать в принципе. Все правильно.

Такие структуры используются для наложения на уже сущестующую память.

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


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

И не может работать в принципе. Все правильно.

 

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

 

А что значит, наложение на уже существующую память?

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


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

Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но как, допустим, определить массив Ваших структур??? И как, допустим, в цикле их перебирать если все структуры разной длины???

 

Кстати, можете показать код инициализации члена Text[] структуры Menu_Item? Что то у меня не получилось :)

 

А я так работаю. И ни единого глюка нет, хотя код сейчас 56к. У меня правда определён один массив в конце структуры. Работаю я через кучу и указатели. То есть при создании экземпляра создаётся указатель на структуру. При вызове используется данный указатель. Использую и массивы структур и сортировку. Никаких проблем. Структуры имеют разные поля и разные массивы. Создаются и удаляются.

 

Единственное, что я упростил диспетчер кучи. Поленился. Надо будет попробовать последовать совету zltigo и написать свой.

 

Что особенно хочется отметить, это отличную работу отладчика (пользую IAR_C-AVR_Studio) со всем этим барахлом. Я думал будет намного хуже. Не смотри что указатели. Полный доступ к полям.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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