Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Инициализация структуры. Что не так?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
SasaVitebsk
Написал симулятор и отладил в QT4. Всё работает, достаточно объёмный проект.
Начал переносить на целевую платформу в IAR.
Споткнулся на ровном месте. Хотелось бы решить "в лоб", так как по-другому очень большой кусок работы.
Помогите.
Есть объявление структуры:
Код
// хранится во флэши
typedef struct
{
  int8_t               *Index;         // Указатель на редактируемый параметр/ смещение для каналов
  uint16_t              Number;         // Число пунктов
  uint16_t                Ch;                // 0/ Указатель на канал
  uint8_t               *ItemName[];    // Указатели на имена пунктов
} RadioBtn_t;

Есть строки:
Код
uint8_t const    sFlowControlComport[3][9] = {"None","Hard","Xon/Xoff"};

Есть объявление:
Код
//***************************************************************
// @@ 1312. Управление потоком
RadioBtn_t rbtFlowControl =
{
    0,                                            // Указатель на редактируемое значение
    3,                                            // Всего 3 пункта,
    ((uint32_t)&ComSetting[0].flowcontrol- (uint32_t)ComSetting),    // flowcontrol
    {sFlowControlComport[NONE], sFlowControlComport[HARD], sFlowControlComport[SOFT]}
};

Qt компилирует правильно и никаких вопросов у него это не вызывает
У IAR ARM 6.4.02 возникает 2 ошибки
1 - в строке 4 структуры у него претензия, что это не константа, но на самом деле это смещение адресов и должно вычислятся на этапе компиляции. Не вижу здесь проблемы и QT тоже не видит. Как это объяснить IAR?
2 - IAR в строке 5 пишет: слишком много параметров инициализации. Честно говоря, тоже не вижу проблемы.
Понятно что я могу указать лишь только имя масива и смещаться на длину элемента, но здесь я привожу только частный случай. Есть места, где это разные строки произвольной длины, так что такой метод не предлагать. Хотелось бы поэкономить место. Не хотелось бы также создавать отдельный масив указателей - тоже + 4 байта на один радиобутон. Поскольку элементов очень много, то будет набегать. Ну и QT почемуто понимает меня и работает как нужно. Поэтому непонятно ...
Какие будут предложения?
Заранее благодарю всех откликнувшихся ...
MrYuran
Цитата
uint8_t const sFlowControlComport[3][9] = {"None","Hard","Xon/Xoff"};


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

uint8_t const* sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};

По-моему, так.

Компилятор составит таблицу указателей на ascii-строки
GetSmart
По поводу ошибки номер раз. Воспользуйтесь дефайном offsetof()

Он гораздо яснее для понимания задумки программера.

Цитата(SasaVitebsk)
Поскольку элементов очень много, то будет набегать. Ну и QT почемуто понимает меня и работает как нужно. Поэтому непонятно ...

Напоминает Борланд Билдер, препроцессор и sizeof sm.gif

Вопрос стоит как это должно быть по стандарту. С пояснением от какого года стандарт.
SasaVitebsk
Цитата(GetSmart @ Sep 6 2012, 16:39) *
По поводу ошибки номер раз.

Спасибо огромное. Ошибку номер раз закрыли. cheers.gif

Цитата(MrYuran)
Обычно это несколько по-другому пишется, если имеются в виду константные строки.

Имеется ввиду именно это, но IAR не позволяет инициализировать двухмерный массив, если младшее измерение открыто. По-моему другие компиляторы тоже.
То есть Ваше объявление не проходит.
uint8_t const sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};
Error[Pe144]: a value of type "char [5]" cannot be used to initialize an entity of type "unsigned char const [3]" E:\work\IAR C Proect\tm3\Source\var.c 86

Вот такое, естественно, пройдёт
uint8_t const sFlowControlComport[] = {"None"};
MrYuran
Цитата(SasaVitebsk @ Sep 6 2012, 17:08) *
Имеется ввиду именно это, но IAR не позволяет инициализировать двухмерный массив, если младшее измерение открыто. По-моему другие компиляторы тоже.
То есть Ваше объявление не проходит.

Он одномерный, содержит указатели на начала строк.
Звездочку возле const* забыли sm.gif
scifi
Цитата(SasaVitebsk @ Sep 6 2012, 17:08) *
Имеется ввиду именно это, но IAR не позволяет инициализировать двухмерный массив, если младшее измерение открыто. По-моему другие компиляторы тоже.

Это массив указателей. Посмотрите внимательнее: там должна быть звёздочка. Ну и если строки не меняются, то const можно написать 2 раза:
Код
const char* const foobar[] = { "one", "two", "three" };
Сергей Борщ
QUOTE (SasaVitebsk @ Sep 6 2012, 16:08) *
То есть Ваше объявление не проходит.
uint8_t const sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};
Error[Pe144]: a value of type "char [5]" cannot be used to initialize an entity of type "unsigned char const [3]" E:\work\IAR C Proect\tm3\Source\var.c 86
"Смешались в кучу кони, люди", uint8_t, char, указатели...
Вы хотите массив из трех указателей на строки символов, а объявляете массив из трех беззнаковых 8-битных чисел.
Попробуйте все же объявлять массив указателей, и указателей именно на char:
char const * const sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};
SasaVitebsk
Спасибо большое. Что-то вчера, к концу рабочего дня мозги уже не работали.
Вариант "const uint8_t* const sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};" работает, собственно как и мой первоначальный.
Проблема то не в этом.
Проблема в объявлении структуры

Код
// @@ 1312. Управление потоком
RadioBtn_t rbtFlowControl =
{
    0,                                            // Указатель на редактируемое значение
    3,                                            // Всего 3 пункта,
    offsetof(ComSetting_t,flowcontrol),            // flowcontrol
    {sFlowControlComport[NONE], sFlowControlComport[HARD], sFlowControlComport[SOFT]}
};

Error[Pe146]: too many initializer values E:\work\IAR C Proect\tm3\Source\MonoMenu\lcd_work.c 346
Объявление структуры - в посте выше.
Ещё раз отмечаю - QT скомпилировал и прекрасно работал
MrYuran
Цитата(SasaVitebsk @ Sep 7 2012, 09:54) *
Вариант "const uint8_t* const sFlowControlComport[3] = {"None","Hard","Xon/Xoff"};" работает, собственно как и мой первоначальный.

Вот и чудненько.
Код
// @@ 1312. Управление потоком
RadioBtn_t rbtFlowControl =
{
    0,                                            // Указатель на редактируемое значение
    3,                                            // Всего 3 пункта,
    offsetof(ComSetting_t,flowcontrol),            // flowcontrol
    sFlowControlComport[]
};

demiurg_spb
Код
typedef struct
{
  int8_t*            Index;
  uint16_t           Number;
  uint16_t           Ch;
  const char* const* ItemName;
} RadioBtn_t;

const char* const sFlowControlComport[] = {"None", "Hard", "Xon/Xoff"};

const RadioBtn_t btn =
{
    (void*)0,
    0,
    0,
    sFlowControlComport
};

int main(void)
{
    puts(btn.ItemName[0]);
    puts(btn.ItemName[1]);
    puts(btn.ItemName[2]);

    return (0);
}
output:
Код
None
Hard
Xon/Xoff
scifi
Кстати, как-то не очень хорошо выглядит эта структура:
Код
typedef struct
{
  int8_t   *Index;
  uint16_t Number;
  uint16_t Ch;
  uint8_t  *ItemName[];
} RadioBtn_t;

В конце она содержит массив неопределённого размера.
Лучше применить указатель на массив строк:
Код
typedef struct
{
  int8_t   *Index;
  uint16_t Number;
  uint16_t Ch;
  char const * const *ItemName;
} RadioBtn_t;
SasaVitebsk
Цитата(scifi @ Sep 7 2012, 10:24) *
Кстати, как-то не очень хорошо выглядит эта структура:
В конце она содержит массив неопределённого размера.

Именно это я и хотел!
Я показал один вариант, когда у меня массив указателей, но в других элементах интерфейса, может быть просто несколько несвязанных указателей.
Если я укажу просто масив указателей, то дополнительные затраты - 1 указатель. Элементов много и набежит прилично.
Оно конечно не критично, но просто переписать придётся. Там где применены разрозменные строки, то надо добавить массив указателей.
demiurg_spb
Зато размер структуры RadioBtn_t будет значительно меньше (всего один указатель на массив строк вместо N указателей на каждую строку). ОЗУ экономится...
Это, я думаю, должно быть первично. Тем более, если вы говорите, что их у вас много набегает.
SasaVitebsk
rolleyes.gif Я буду добиваться, чтобы всё во флэш легло. Это обычное графическое меню, для 128*64. И в озу ему делать нечего ... biggrin.gif
demiurg_spb
Не выйдет. Нельзя в си инициализировать константу константой...
например так нельзя:
Код
const int x = 3;
const int y = x;  // никак, обидно:-(

и так нельзя:
Код
const RadioBtn_t rbtFlowControl =
{
    0,
    3,
    offsetof(ComSetting_t,flowcontrol),
    {sFlowControlComport[NONE], sFlowControlComport[HARD], sFlowControlComport[SOFT]}  // это невозможно при наличии const квалификатора у типа этой rbtFlowControl структуры.
};

разве что:
Код
typedef struct
{
  int8_t*     Index;
  uint16_t    Number;
  uint16_t    Ch;
  const char* ItemName[];
} RadioBtn_t;

const char sFlowControlComportNone[]    = "None";
const char sFlowControlComportHard[]    = "Hard";
const char sFlowControlComportXonXoff[] = "Xon/Xoff";

const RadioBtn_t btn =
{
    (void*)0,
    0,
    0,
    {
        sFlowControlComportNone,
        sFlowControlComportHard,
        sFlowControlComportXonXoff
    }
};
И keil и gcc (правда gcc только при включенной опции --pedantic) ругаются на сие, но по-разному:
Код
keil: main.c(26): error:  #146: too many initializer values
gcc: main.c:26:2: error: initialization of a flexible array member [-Werror=pedantic]

Думаю, что keil не прав, но от этого вам не легче. И переписать всё-же придётся чтобы был нормально переносимый код.
Я обычно когда сомневаюсь в чём-то (правда уже редко это бывает) сразу на разных компиляторах прогоняю тестики и делаю выводы о том что такое хорошо, а что такое плохо.
Безотносительно даже стандарта Си...
Вы кстати добавьте следующие ключи компиляции к gcc (если у вас он установлен) узнаете много нового о своих программах:-)
-std=c99
-pedantic
-Wall
-Wextra
-Werror
SasaVitebsk
Переписываю, хотя честно говоря - непонятно. Почему он не может мне в конце просто перечислить указатели как я хочу.
Почему QT это делает без проблем. В смысле MinGW как я понимаю.
Пока только радиобоксы... Причём и сам обработчик придся переписать. Создать некоторые масивы указателей.
Потом чекбоксы, списки и многое другое. В целом прибавил себе 3-4 дня работы ... wacko.gif
demiurg_spb
А вы в QT проект с++ или си делали?
Если си, то попробуйте ключики, о которых я говорил.
А так действительно ситуация немного странная с кейлом и видимо с иаром.
Т.к. gcc может это прожевать при определённых условиях.

PS:
На одном из форумов была цитата раздела 6.7.2.1 си-стандарта:
A structure type containing a flexible array member is an incomplete type that cannot be completed

Получается ничего странного нет - это видимо gnu расширение языка си.
scifi
Цитата(demiurg_spb @ Sep 7 2012, 12:09) *
Безотносительно даже стандарта Си...

Кстати, вот что по этому поводу говорит стандарт C99:
Цитата
If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.

Так что по стандарту всё должно работать.
SasaVitebsk
Цитата(demiurg_spb @ Sep 7 2012, 14:56) *
А вы в QT проект с++ или си делали?

Все файлы, которые я планировал переносить - чистый си.
Перед этим я так делал с цветным дисплеем - всё прокатило и мне понравилось ... Кстати посмотрю как я там делал.
Помню, что где-то я уже такое делал ... Только не помню как. Но точно помню, что не ключами ...
Толи задавал минимальный размер, а инициализировал реальным значением ... Хоть убей не помню. (
MrYuran
Цитата(demiurg_spb @ Sep 7 2012, 15:56) *
Получается ничего странного нет - это видимо gnu расширение языка си.

Так и есть.
GCC позволяет включать в структуры открытый массив, если он размещен последним.
ReAl
Цитата(MrYuran @ Sep 7 2012, 15:51) *
GCC позволяет включать в структуры открытый массив, если он размещен последним.

Это (иметь такой массив в структуре) позволяет C99.
Цитата
6.7.2.1 Structure and union specifiers
...
Semantics
...
16 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. Second, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
Просто инициализация такого массива не входит в планы :-)

Зато позволяется такое (можете пробовать с -std=c99 --pedantic):
Код
#include <stdlib.h>

typedef struct {
    int head, tail, size;
    int data[];
} fifo_t;

fifo_t *create_fifo(int size)
{
    fifo_t *pf = (fifo_t*)malloc(sizeof(fifo_t)+size*sizeof(int));
    if (pf) {
        pf->head = pf->tail = 0;
        pf->size = size;
    }
    return pf;
}
...
    // И затем так
    pf->data[head++] = a;
    // Что абсолютно корректно, так как
    // it behaves as if that member were replaced with the longest array
    // that would not make the structure larger than the object being accessed

Думаю, для этого в стандарт и было введено. До C99 извращались так:
Код
typedef struct {
    int head, tail, size;
    int data[1];
} fifo_t;

    fifo_t *pf = (fifo_t*)malloc(sizeof(fifo_t)+(size-1)*sizeof(int));
Некоторые компиляторы в качестве расширения позволяли
Код
typedef struct {
    int head, tail, size;
    int data[0];
} fifo_t;
MrYuran
Цитата(ReAl @ Sep 7 2012, 18:03) *
Это (иметь такой массив в структуре) позволяет C99.

А в ИАРе какой стандарт по умолчанию?
Может, просто ключик повернуть?
ReAl
Цитата(MrYuran @ Sep 7 2012, 17:10) *
А в ИАРе какой стандарт по умолчанию?
Может, просто ключик повернуть?
Так инициализация такого массива (и, фактически, изменение sizeof структуры, смена типа объекта) не входит в C99.
Это уже gnu99
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.