Форум программистов, компьютерный форум, киберфорум
Наши страницы
C для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
1

Удивительная ошибка при инициализации структур

06.12.2016, 22:18. Просмотров 878. Ответов 14
Метки нет (Все метки)

Вот так работает нормально:
C
1
2
3
4
5
6
7
8
9
10
struct SMenu
 {
 char *MenuItems[],Id,Sel,Len;
 struct SMenu *Parent;
 };
 
#define MLen(M) sizeof((M).MenuItems)/sizeof(char*) 
 
struct SMenu M0={{"123","456","678"},0,0,MLen(M0),&M0};
 struct SMenu M01={{"qqqq","www","eee"},0,0,MLen(M01),&M0};
Вот так тоже:
C
1
2
3
4
5
6
7
8
9
10
struct SMenu
 {
 char *MenuItems[],Id,Sel,Len;
 struct SMenu *Parent;
 };
 
#define MLen(M) sizeof((M).MenuItems)/sizeof(char*) 
 
struct SMenu M0={{"123","456","678","9100"},0,0,MLen(M0),&M0};
 struct SMenu M01={{"qqqq","www","eee"},0,0,MLen(M01),&M0};
И даже вот так:
C
1
2
3
4
5
6
7
8
9
10
struct SMenu
 {
 char *MenuItems[],Id,Sel,Len;
 struct SMenu *Parent;
 };
 
#define MLen(M) sizeof((M).MenuItems)/sizeof(char*) 
 
struct SMenu M0={{"123","456","678","9100"},0,0,MLen(M0),&M0};
 struct SMenu M01={{"qqqq","www","eee","rrrr"},0,0,MLen(M01),&M0};
А вот так "missing }":
C
1
2
3
4
5
6
7
8
9
10
struct SMenu
 {
 char *MenuItems[],Id,Sel,Len;
 struct SMenu *Parent;
 };
 
#define MLen(M) sizeof((M).MenuItems)/sizeof(char*) 
 
struct SMenu M0={{"123","456","678"},0,0,MLen(M0),&M0};
 struct SMenu M01={{"qqqq","www","eee","rrrr"},0,0,MLen(M01),&M0};
Моя логика отказывается это понимать(((
0
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.12.2016, 22:18
Ответы с готовыми решениями:

Динамический массив структур - Ошибка "значение int* нельзя использовать для инициализации сущности типа TRGB"
требуется создать динамический массив структур, т.е. он не совсем динамический,...

Ошибка при инициализации поля структуры
При инициализации поля структуры в массиве структур вылетает ошибка. Подскажите...

Ошибка при копировании структур
При копировании структур, выдает ошибку, подскажите, почему? #include<stdio.h>...

Ошибка при использовании структур
Мне задали очень странное дополнительное задание. Организовать многочлены, с...

Ошибка при сортировке массива структур
Всем привет! пишу компресор по Хаффману столкнулся с неожиданной проблемой не...

14
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
06.12.2016, 22:50 2
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Вот так работает нормально:
Это какой это компилятор вам такое разрешил?

В языке С массив c размером [] может быть последним и только последним полем структуры. Ваше объявление структуры не компилируемо в принципе ни в одном из вариантов.

Если вы нашли какой-то компилятор, который это принимает, то читайте его документацию на предмет того, что это вообще такое, как это должно работать и что у него там за "логика".
1
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
06.12.2016, 22:56  [ТС] 3
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Это какой это компилятор вам такое разрешил?
Это компилятор под AVR.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В языке С массив c размером [] может быть последним и только последним полем структуры.
Спасибо, не знал про это требование.
C
1
2
3
4
5
6
7
8
9
10
struct SMenu
 {
 char Id,Sel,Len;
 struct SMenu *Parent;
 char *MenuItems[];
 };
 
#define MLen(M) sizeof((M).MenuItems)/sizeof(char*) 
 
struct SMenu M0={0,0,MLen(M0),&M0,{"123","456","678"}};
Только теперь макрос работать перестал, "incomplete type is not allowed".
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
06.12.2016, 23:06 4
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Спасибо, не знал про это требование.
Он не просто "может быть последним и только последним полем структуры", но еще и инициализироваться через {} в принципе не может. Массив с размером [] в конце структуры предназначен для структур переменного размера, выделяемых в динамической памяти (т.е. через malloc). При явном объявлении объекта такого типа массив всегда будет иметь размер 0.

То есть то, что вы пытаетесь сделать - такого в С нет в принципе. Хотя, конечно, не мешало бы сначала пояснить, что именно вы пытаетесь сделать.

Наугад можно предложить

C
1
2
3
4
5
6
7
8
9
10
11
12
13
struct SMenu
{
  const char **MenuItems;
  char Id,Sel,Len;
  struct SMenu *Parent;
};
 
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
 
#define MENU_INIT(id, sel, parent, items) { items, id, sel, ARRAY_SIZE(items), parent }
 
struct SMenu M0 = MENU_INIT(0, 0, &M0, ((const char *[]) { "123", "456", "678" }));
struct SMenu M01 = MENU_INIT(0, 0, &M0, ((const char *[]) { "qqqq", "www", "eee" }));
0
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
06.12.2016, 23:07  [ТС] 5
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Хотя, конечно, не мешало бы сначала пояснить, что именно вы пытаетесь сделать.
Я пытаюсь сделать произвольное меню, разумеется с произвольным ветвлением в подменю, чтобы при добавлении нового функционала в проект не пришлось каждый раз переписывать половину программы, а так просто добавить нужное действие по Id.
Соответственно,
*MenuItems[] - это список пунктов меню, которое в данные момент изображается на дисплее
Id - идентификатор действия, если 0 - то меню не конечное и надо выбирать подпункты дальше
Sel - номер выделенного пункта
Len - кол-во строк (должен считать компилятор, чтобы прога не считала каждый раз)
*Parent - указатель на предыдущее меню для возврата

Если у вас есть идеи, как это более рационально реализовать, буду рад выслушать.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
06.12.2016, 23:09 6
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Если у вас есть идеи, как это более рационально реализовать, буду рад выслушать.
См вариант выше. Это попытка угадать и реализовать то, что вы пытались реализовать. А рационально это или нет (или наоборот только захламляет код макросами) - это вопрос отдельный.
0
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
06.12.2016, 23:13  [ТС] 7
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Наугад можно предложить
invalid type conversion

Добавлено через 2 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
или наоборот только захламляет код макросами
Да макрос там только для сокращения длины строки был.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
06.12.2016, 23:13 8
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
invalid type conversion
Компилятор времен царя Гороха?

Compound literals типа (const char *[]) { "123", "456", "678" } - фича C99 и выше.

http://coliru.stacked-crooked.com/a/b55a56103de8899d
0
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
06.12.2016, 23:17  [ТС] 9
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Компилятор времен царя Гороха?
AVR-GCC 2009 года вроде
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
06.12.2016, 23:32 10
Лучший ответ Сообщение было отмечено Kukuxumushu как решение

Решение

Цитата Сообщение от Kukuxumushu Посмотреть сообщение
AVR-GCC 2009 года вроде
Ну может он по умолчанию работает в режиме C89/90, а для перехода в режим C99 надо указать -std=c99?

Добавлено через 4 минуты
В С89/90 пришлось бы обходится без compound literals и делать что-то вроде

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct SMenu
{
  const char **MenuItems;
  char Id,Sel,Len;
  struct SMenu *Parent;
};
 
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
 
#define MENU_INIT(id, sel, parent, items) { items, id, sel, ARRAY_SIZE(items), parent }
 
static const char *M0_Items[] = { "123", "456", "678" };
struct SMenu M0 = MENU_INIT(0, 0, &M0, M0_Items);
 
static const char *M01_Items[] = { "qqqq", "www", "eee" };
struct SMenu M01 = MENU_INIT(0, 0, &M0, M01_Items);
1
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
06.12.2016, 23:52  [ТС] 11
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В С89/90 пришлось бы обходится без compound literals и делать что-то вроде
Вот так всё чётко компилируется, только если без const. Правда, пока не знаю что выдаст первый макрос и не могу понять зачем нужен второй?

Добавлено через 4 минуты
Первый макрос проверил, чётко отрабатывает, и вообще прога всё верно выдаёт.

Добавлено через 5 минут
Убрал второй макрос, всё чётко работает, благодарю за квалифицированную помощь!
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct SMenu
{
  const char **MenuItems;
  char Id,Sel,Len;
  struct SMenu *Parent;
};
 
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
 
char *M0_Items[] = { "123", "456", "678" };
struct SMenu M0 ={M0_Items,0,0,ARRAY_SIZE(M0_Items),&M0};
 
char *M01_Items[] = { "qqqq", "www", "eee","rrrr" };
struct SMenu M01 ={M01_Items,0,0,ARRAY_SIZE(M01_Items),&M0};
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
07.12.2016, 00:37 12
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
только если без const.
Не совсем понятно, какие могли быть проблемы с const, если учесть, что в объявлении структуры вы const таки оставили...

Цитата Сообщение от Kukuxumushu Посмотреть сообщение
не могу понять зачем нужен второй
В исходном С99 варианте он был нужен, а здесь - да, необходимости в нем уже нет.
0
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
07.12.2016, 17:37  [ТС] 13
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Не совсем понятно, какие могли быть проблемы с const, если учесть, что в объявлении структуры вы const таки оставили...
Это как-то связано особенностью контроллеров. Константы компилятор размещает во флеш-память, а вот обратно их вытащить при инициализации структуры почему-то не может, и второй раз всё копирует в ОЗУ. Но проблема как-то должна решаться.

Добавлено через 15 часов 56 минут
TheCalligrapher, проблемы с памятью я решил, а вы бы не могли помочь с макросом?
Надо вот это
C
1
SetMenu(01,5,{"123","456","7890"},2)
превращать вот в это
C
1
2
eeprom char *M01_Items[]={"123","456","7890"}; 
struct SMenu M01={M01_Items,5,0,sizeof(M01_Items)/sizeof*(M01_Items),&M02};
Параметры, думаю, понятны, 0 (который поле 5) - передавать не надо, всегда должно им инициализироваться это поле.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4848 / 2492 / 696
Регистрация: 18.10.2014
Сообщений: 4,320
07.12.2016, 21:29 14
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
превращать вот в это
Мне непонятно, что такое последний аргумент 2. Если это то, что превратилось в &M02, то почему тогда аргумент указан как 2, а не 02?

В любом случае проблема тут с тем, что препроцессор будет "видеть" запятые в {"123","456","7890"}, как разделители аргументов. Чтобы в такой ситуации предложить более-менее элегантое решение, понадобятся свойства препроцессора C99, т.е. макро с переменным числом параметров и __VA_ARGS__.

А без этого навскидку можно предложить разве что

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)
 
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
 
#define SetMenu(suffix, id, items, parent_suffix)\
  eeprom char *CONCAT(Items_M, suffix)[] = items;\
  struct SMenu CONCAT(M, suffix) =\
  {\
    CONCAT(Items_M, suffix),\
    id, 0,\
    ARRAY_SIZE(CONCAT(Items_M, suffix)),\
    &CONCAT(M, parent_suffix)\
  };
и потом использование как

C
1
2
3
4
5
6
7
8
9
10
11
#define ITEMS { "abc", "def", "ghi" }
SetMenu(0, 1, ITEMS, 0)
#undef ITEMS
 
#define ITEMS { "qqqq", "www", "eee", "rrrr" }
SetMenu(02, 8, ITEMS, 0)
#undef ITEMS
 
#define ITEMS { "123", "456", "7890" }
SetMenu(01, 5, ITEMS, 02)
#undef ITEMS
Кривовато, но пока так...
1
Kukuxumushu
1589 / 586 / 107
Регистрация: 13.06.2015
Сообщений: 1,998
Завершенные тесты: 2
07.12.2016, 22:01  [ТС] 15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если это то, что превратилось в &M02, то почему тогда аргумент указан как 2, а не 02?
Извиняюсь, очепятался)
Несмотря на всю тупость препроцессора, ваш вариант прекрасно работает!
И в финале мне бы хотелось разместить весь этот набор (а там много пунктов будет) в массиве автоматически вычисляемого размера, чтобы переход в субменю можно было организовать простым сложением текущего индекса полем Sel. Скажите, такое вообще возможно?
0
07.12.2016, 22:01
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.12.2016, 22:01

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

Ошибка в инициализации
Пишет ошибка при инициализировании min Помогите, пожалуйста #include...

Ошибка в инициализации массива указателей на функции
Как правильно инициализировать массив указателей на функции? Компилятор...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru