Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR(Ну или C) + Массивы в структуре
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Quasar
При таком определении компилятор ругается:
Код
typedef struct {  
    const char  Engl[];
    const char  Russ[];
} LangStruct PROGMEM;


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

Собственно вопрос, а возможно ли вообще в С размещать таким образом два массива?
prottoss
Цитата(Quasar @ Jul 30 2007, 19:33) *
При таком определении компилятор ругается:
Код
typedef struct {  
    const char  Engl[];
    const char  Russ[];
} LangStruct PROGMEM;


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

Собственно вопрос, а возможно ли вообще в С размещать таким образом два массива?
Нет конечно! Ни один, ни два и не десять массивов (в структуре или нет) так определять нельзя. И компилятор ругается справедливо, ибо размеры массивов не заданы, соответственно, компилятор не знает, сколько памяти надо для размещения переменной такого типа.
Quasar
Цитата(prottoss @ Jul 30 2007, 15:43) *
Нет конечно! Ни один, ни два и не десять массивов (в структуре или нет) так определять нельзя. И компилятор ругается справедливо, ибо размеры массивов не заданы, соответственно, компилятор не знает, сколько памяти надо для размещения переменной такого типа.


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

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


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

Да, и к тому же опеределение типа
extern char mass[]; тоже вполне работает, но это уже отдельный разговор...
prottoss
Можно сделать немного по другому, если Вы не знаете точно, какой длины массивы будут

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

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

[/quote]



Цитата(Quasar @ Jul 30 2007, 19:48) *
Почему это ни одного?

Код
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??? Зеро байт? smile.gif Или миллион?
Quasar
Цитата(prottoss @ Jul 30 2007, 15:53) *
Можно сделать немного по другому, если Вы не знаете точно, какой длины массивы будут

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

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

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

Цитата
Интересно, а какой размер массива Text??? Зеро байт? smile.gif Или миллион?


А ни какой, это примерно аналогично extern char Mass[], то есть происходит определение, а память выделяется при создании экземпляра.
prottoss
Цитата(Quasar @ Jul 30 2007, 20:00) *
А ни какой, это примерно аналогично extern char Mass[], то есть происходит определение, а память выделяется при создании экземпляра.
ИМХО это очччень не хорошо, если это на самом деле работает. Ни когда не известно, какого размера структура 07.gif
umup
В определении типа не нужно указывать атрибутов (PROGMEM), они указываются при обьявлении переменных этого типа :
Код
typedef struct {  
    const char  Engl[size1];
    const char  Russ[size2];
} LangStruct;

LangStruct PROGMEM str1;
LangStruct EEPROM str2;


в данном случае str1 будет размещена в программной памяти, str2 - в eeprom. size1, size2 должны быть определены перед обьявлением типа...
Quasar
Цитата
ИМХО это очччень не хорошо, если это на самом деле работает. Ни когда не известно, какого размера структура


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

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


Ну почему же не нужно, смотря для чего, в данном случае надо что бы всё было во флеш, зачем же тогда по сто раз PROGMEM писать. smile.gif
prottoss
Цитата(Quasar @ Jul 30 2007, 20:19) *
Ну почему не известно, длинна всех типов в структуре, плюс длинна массива, полученная при инициализации, так получается. Кстати именно поэтому видимо и требование такое, что бы массив был в конце структуры, вот два и не получится разместить crying.gif .
Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но как, допустим, определить массив Ваших структур??? И как, допустим, в цикле их перебирать если все структуры разной длины???

Кстати, можете показать код инициализации члена Text[] структуры Menu_Item? Что то у меня не получилось smile.gif
Quasar
Цитата(prottoss @ Jul 30 2007, 16:51) *
И как, допустим, в цикле их перебирать если все структуры разной длины???


Да, с перебором в цикле - проблема smile.gif . Но как Вы могли догадаться, в массиве Text[] храниться текст smile.gif , и вообщем-то данный приём только для текста-то и полезен, ибо в цикле чаще всего стоит условие 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
ReAl
Цитата(prottoss @ Jul 30 2007, 14:51) *
Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но

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

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

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

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

Без проблем.
Код
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
CODE
.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);



Но проблемой этих выкрутасов было в том числе то, что компилятор не запрещал создать массив таких структур. А теперь может выдать ошибку.
prottoss
Цитата(ReAl @ Jul 30 2007, 22:20) *
[code]typedef struct {
int i;
char c[];
} s;

s s1 = { 1, "abc" };
s s2 = { 1, "qwerty" };
В IAR (по крайней мере в версии 4.10, что у меня) это не работает.



И ИМХО - это правильно (что не работает smile.gif ).
zltigo
Цитата(prottoss @ Jul 30 2007, 17:24) *
И ИМХО - это правильно (что не работает smile.gif ).

И не может работать в принципе. Все правильно.
Такие структуры используются для наложения на уже сущестующую память.
Quasar
Цитата(zltigo @ Jul 30 2007, 21:04) *
И не может работать в принципе. Все правильно.


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

А что значит, наложение на уже существующую память?
SasaVitebsk
Цитата(prottoss @ Jul 30 2007, 15:51) *
Хм... Я, конечно, не знаю, как Вы там в программе работаете с этими структурами, но как, допустим, определить массив Ваших структур??? И как, допустим, в цикле их перебирать если все структуры разной длины???

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


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

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

Что особенно хочется отметить, это отличную работу отладчика (пользую IAR_C-AVR_Studio) со всем этим барахлом. Я думал будет намного хуже. Не смотри что указатели. Полный доступ к полям.
singlskv
Цитата(zltigo @ Jul 30 2007, 21:04) *
И не может работать в принципе. Все правильно.
Такие структуры используются для наложения на уже сущестующую память.

Эээ...
Ну вобще-то в последних стандартах С, массив 0 длинны в структуре весчь вполне законная
насколько я помню...
Хотя если ткнете мордой в последний стандарт где будет сказанно что это не так, то соглашусь...
Сергей Борщ
Цитата(zltigo @ Jul 30 2007, 20:04) *
И не может работать в принципе. Все правильно.
Может работать и работает. С позволяет.
Цитата
A structure or union shall not contain a member with incomplete or function type (...), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
Размер такой структуры определяется как размер всех элементов без массива:
Цитата
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. With two exceptions, the flexible array member is ignored. First, the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length
А вот в С++ - не работает и не должно.
zltigo
Цитата(Сергей Борщ @ Jul 31 2007, 11:39) *
Может работать и работает. С позволяет. Размер такой структуры определяется как размер всех элементов без массива:А вот в С++ - не работает и не должно.

Речь шла не о получении размера а об ИНИЦИАЛИЗАЦИИ последнего элемента такой структуры. Смотри внимательнее.
ReAl
Цитата(zltigo @ Jul 31 2007, 15:52) *
Речь шла не о получении размера а об ИНИЦИАЛИЗАЦИИ последнего элемента такой структуры. Смотри внимательнее.
Мммм....
Да. Жаль. А я почти привык, а оно gcc-шное расширение, наверное, надо глянуть.
Цитата
17 EXAMPLE Assuming that all array members are aligned the same, after the declarations:
struct s { int n; double d[]; };
struct ss { int n; double d[1]; };
the three expressions:
sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)
have the same value. The structure struct s has a flexible array member d.
...
18 If sizeof (double) is 8, then after the following code is executed:
struct s *s1;
struct s *s2;
s1 = malloc(sizeof (struct s) + 64);
s2 = malloc(sizeof (struct s) + 46);
and assuming that the calls to malloc succeed, the objects pointed to by s1 and s2 behave as if the
identifiers had been declared as:
struct { int n; double d[8]; } *s1;
struct { int n; double d[5]; } *s2;
...
20 The assignment:
*s1 = *s2;
only copies the member n and not any of the array elements. Similarly:
struct s t1 = { 0 }; // valid
struct s t2 = { 2 }; // valid
struct ss tt = { 1, { 4.2 }}; // valid
struct s t3 = { 1, { 4.2 }}; // invalid: there is nothing for the 4.2 to initialize
...

Так что законно только наложение на память. Посыпаю голову пеплом.

Хотя странно и, на мой взгляд - нелогично, почему-то
int ii[] = { 1, 2, 3};
char *tbl[] = { "Hello, ", "world!", 0 };
т.е. "уточнение" размера массива при инициализации для этих incomplete array было возможно всегда, хотя тут тоже не указано выделение памяти числом в скобках и тоже можно сказать "there is nothing to initialize".
А помещение их в хвост структуры эту возможность отбило.
SasaVitebsk
А чего Вы расстраиваетесь. Напишите свою инициализацию. В одном из полей (к примеру, естественно можно и по другому) структуры введите её длину. И работайте.

При присвоении - определяете изаносите длину. Выделяете память. При удалении освобождаете память указанной длины.
Maddy
Цитата(ReAl @ Jul 31 2007, 19:11) *
Мммм....
Да. Жаль. А я почти привык, а оно gcc-шное расширение, наверное, надо глянуть.

Гы wink.gif Далеко не gcc ж) Это пол WIN API на этом построено .... первым элементом структуры размер , а результат - в зависимости от него wink.gif Таки IMHO все законно ... Но вариант с двумя элеметами неизвестного размера(на этапе компиляции) непройдет .... И тож законно ...
ReAl
Цитата(Maddy @ Jul 31 2007, 22:01) *
Это пол WIN API на этом построено .... первым элементом структуры размер , а результат - в зависимости от него ;
Что-то я ни разу не видел статической инициализации incomplete array в конце структуры в WinAPI. Особенно учитывая то, что традиция с размером структуры в первом её поле в винАПИ тянется с тех пор, когда этих incomplete хвостов в структурах в стандарте С ещё не было, они в С99 появились, а в Win3.1 уже давно и в полный рост использовалось хранение размера в самой структуре.
Там просто структуры разрастались, позже дописывались поля и размер структуры в первом слове нужен для определения того, что именно программа (скомпилированная, возможно, для позапрошлой версии виндовс АПИ) понимает под данной структурой.
Т.е. версия1
struct foo {
int size;
int moo, kwa;
};
версия 2
struct foo {
int size;
int moo, kwa;
long ia_ia_ia;
};

Так вот чтобы в винде с версией 2 API программе, которая рассчитана на версию 1 винда, записывая это ia_ia_ia не затёрла какие-то переменные - и введён размер в начале. К неполным массивам и статической их инициализации это не имеет никакого отношения. И даже к наложению таких структур на динамически выделенную память.
sensor_ua
Цитата
введён размер в начале. К неполным массивам и статической их инициализации это не имеет никакого отношения

Думал, что в винде это натянутая совместимость с базами данных - тип PSTRING в Clarion содержал длину в начале, а потом собственно строку. Да и какие-то сортировки/поиски в винде на это таки заточены были.
Maddy
Цитата(ReAl @ Aug 1 2007, 00:24) *
Что-то я ни разу не видел статической инициализации incomplete array в конце структуры в WinAPI. Особенно учитывая то, что традиция с размером структуры в первом её поле в винАПИ тянется с тех


Мдя чего-то я погорячился sad.gif "Признаю свою вину ....."© Филатов wink.gif
Методом тыка в мсдн нифига не нашел подобного .... Хотя в мозгах отложилося , что во времена 4 борланда (не билдера) оно было .... ну да фиг с ним - все-равно грабли потенциальные ....


Цитата(sensor_ua @ Aug 1 2007, 08:55) *
Думал, что в винде это натянутая совместимость с базами данных - тип PSTRING в Clarion содержал длину в начале, а потом собственно строку. Да и какие-то сортировки/поиски в винде на это таки заточены были.


А это больше на паскаль похоже wink.gif
Kirill Frolov
Цитата(Quasar @ Jul 30 2007, 15:33) *
При таком определении компилятор ругается:
Код
typedef struct {  
    const char  Engl[];
    const char  Russ[];
} LangStruct PROGMEM;

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


Разумеется. А как он (компилятор) узнает смещение Russ относительно начала структуры, а?
Zero length array МОГУТ (а могут и не) РАЗРЕШАТЬСЯ НЕКОТОРЫМИ КОМПИЛЯТОРАМИ, в число
которых входит и GCC (winavr). При том что C99 требует записи без указания размерности, а некоторые
компиляторы позволяют [0].
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.