|
куча const..., элементарный вопрос по Си |
|
|
|
Aug 29 2009, 05:26
|
Частый гость
 
Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227

|
Дожился...  Помогите чайнику. Итак... вводная: пользую PIC24H, пишу на Си (без плюсов), компилятор - С30, уже скурил весь гугль, учебники по сям... имею определение интерфейса (структуру указателей на функции): Код typedef struct { void (*FunctionPointer) (char Param); int (*OtherFuncPointer) (int SomeParam); .... } PWInterface, *pPWInterface, **ppPWInterface; Далее имеется несколько модулей, реализующих некое поведение и предоставляющих указанный интерфейс: Код заголовочный файл: extern const PWInterface const PWMonitor0; Код сишный файл с реализацией: static void SomeFunc1 (char Param); static void SomeFunc2 (int SomeParam);
const PWInterface const PWMonitor0 = { &SomeFunc1, &SomeFunc2, .... }; ну и далее реализация этих функций. таких модулей несколько, все предоставляют означенный в начале интерфейс. Т.е. я сознательно выделяю память в памяти программ и пишу дважды const. Далее собираю интерфейсы в одну кучу: Код #include "PWMonitor0.h" #include "PWMonitor1.h" #include "PWMonitor2.h" ....................
const PWInterface *const PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor0_c, &PWMonitor0_r}; const PWInterface *const PWMonMode2Arr[] = {&PWMonitor1, &PWMonitor1_r}; const PWInterface *const PWMonMode3Arr[] = {&PWMonitor2}; Т.е. массивы константных указателей на константные структуры заданного типа. конструкцию представленную выше компилятор поглощает без проблем, а если же пользую Код const pPWInterface const PWMonMode1Arr[] = ... получаю warning: initialization discards qualifiers from pointer target typeВопрос первый: Что именно я недопонимаю? Хотел как лучше (чтоб через typedef... красившее. Вроде корректно определенный тип указателя при определении структуры)... Продолжу... далее имея массивы(константные) (константных)указателей на (константные)интерфейсы, собираю их в свою очередь в массив(тоже константный): Код const ppPWInterface const Pathways[] = {&PWMonMode1Arr, &PWMonMode2Arr, &PWMonMode3Arr};
чтоб можно было бы где-то в коде сказать нечто подобное: result = Pathways[PowerMode][ID]->OtherFuncPointer(somecode); Вот тут(при определении массива, а не на вызове метода интерфейса) уже имею трижды warning: initialization from incompatible pointer typeПробовал разные вариации... но, видимо, не все... Вопрос второй: как сделать правильно? Компилятор, в общем-то, понимает что я от него хочу. Память распределяет правильно, инициализирует правильно, все компилируется... но этот варнинг... я ж из-за него невыспался.  Уфффф... спасибо за терпение дочитавшим сий опус
|
|
|
|
|
Aug 29 2009, 14:26
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 23-05-08
Пользователь №: 37 760

|
Я чайник  . И помочь ничем не смогу. Но хочу спросить (в целях самообразования) - а что значит вот это объявление? Цитата(cf7k @ Aug 29 2009, 09:26)  Код заголовочный файл: extern const PWInterface const PWMonitor0; Я в смысле как это укладывается в общую схему объявления переменной? [класс памяти] [const] тип имя [инициализатор] - в данном случае [класс памяти] -extern, тип - структура с именем PWInterface, определенным с помощью typedef, имя переменной - PWMonitor0.... А второй const (...PWInterface const PWMonitor0) - это что такое? А то получается что-то наподобие "extern const int const var1".... Здесь мне тоже ничего не понятно: Цитата(cf7k @ Aug 29 2009, 09:26)  Код const PWInterface const PWMonitor0 = { &SomeFunc1, &SomeFunc2, .... }; Надеюсь, мне по ходу дела объясните  .
|
|
|
|
|
Aug 29 2009, 15:11
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(cf7k @ Aug 29 2009, 08:26)  Дожился...  Я делаю все попроще. typedef void (*VECTORS)(); const VECTORS function[FUNCTION_QTY]={function1, function2, }; вызов: function[function_index](); Поэтому первый вопрос к Вам - зачем указатели на адрес функции, если можно хранить собственно адрес функции.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Aug 29 2009, 15:18
|
Частый гость
 
Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227

|
Цитата(Student Pupkin @ Aug 29 2009, 18:26)  Я чайник  . И помочь ничем не смогу. Но хочу спросить (в целях самообразования) - а что значит вот это объявление? Цитата extern const PWInterface const PWMonitor0; То же, что и полное объявление вместе с инициализацией, но в заголовочный файл вынесено только имя. Т.к. стоит extern - я сообщаю, что полное объявление с инициализацией существует где-то, а другим модулям достаточно знать имя, тип и "модифицируемость" объекта - всё, чтоб обратиться к нему, а компилятору сгенерировать код. Цитата(Student Pupkin @ Aug 29 2009, 18:26)  Я в смысле как это укладывается в общую схему объявления переменной? [класс памяти] [const] тип имя [инициализатор] - в данном случае [класс памяти] -extern, тип - структура с именем PWInterface, определенным с помощью typedef, имя переменной - PWMonitor0.... А второй const (...PWInterface const PWMonitor0) - это что такое? А то получается что-то наподобие "extern const int const var1".... Я исходил из следующих утверждений: Код int *int_ptr; // Модифицируемый указатель на модифицируемый объект const int *int_ptr; // Модифицируемый указатель на константный объект int * const int_ptr; // Константный указатель на модифицируемый объект const int * const int_ptr; // Константный указатель на константный объект Хотя это касается указателей.... а в моем примере... гм... как-то даже по-русски не получается... первый const - разместить в памяти программ, второй -... возможно лишний, но результат компиляции не меняется... возможно пока гонялся за указателями - намудрил лишнего... Цитата(Student Pupkin @ Aug 29 2009, 18:26)  Здесь мне тоже ничего не понятно: Код const PWInterface const PWMonitor0 = { &SomeFunc1, &SomeFunc2, .... }; Надеюсь, мне по ходу дела объясните  . Идея такова: хочу инициализированную структуру, полям которой при инициализации присвоены указатели на функции. Далее считаю, что сами эти функции константы (собсно адреса никуда не перемещаются, и изменять их не надо) - ставлю второй const; далее хочу чтоб сия структура была компилятором создана в памяти программ, а не в секции данных, которая инициализируется все равно из памяти программ в startup коде - вот появляется первый const. Вот примерно таковы мои рассуждения... Цитата(Dog Pawlowa @ Aug 29 2009, 19:11)  Я делаю все попроще.
typedef void (*VECTORS)(); const VECTORS function[FUNCTION_QTY]={function1, function2, };
вызов: function[function_index]();
Поэтому первый вопрос к Вам - зачем указатели на адрес функции, если можно хранить собственно адрес функции. Возможно я некорректно выразился, но ведь в инициализированной структуре хранятся адреса функций. Поэтому первичная структура избыточность не содержит. Далее я объявлял массив содержащий указатели на структуры с адресами функций. Цель всей этой затеи - в зависимости от двух параметров, которые выступают индексами по массивам, вызывать нужную функцию. Реализовать пытался без использования "марсианских писем"... так сказать - попонятней.
|
|
|
|
|
Aug 29 2009, 16:30
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 23-05-08
Пользователь №: 37 760

|
Цитата(cf7k @ Aug 29 2009, 19:18)  Хотя это касается указателей.... а в моем примере... гм... как-то даже по-русски не получается... первый const - разместить в памяти программ, второй -... возможно лишний, но результат компиляции не меняется... возможно пока гонялся за указателями - намудрил лишнего... Угумс  . Про указатели (константный указатель на константу) я знаю. А вот подобное объявление переменных - первый раз вижу (хотя я и так мало чего видел пока в жизни  ). Ну так может попробовать "возможно лишние" const убрать? А то как-то не по ANSI/ISO получается  ... И второй вопрос - Цитата(cf7k @ Aug 29 2009, 19:18)  Далее считаю, что сами эти функции константы А смысл? Если структура объявлена константой, то ее поля изменять нельзя... И потом - по логике константы должны размещаться в ROM. И еще сами функции размещаются в ROM, значит их адреса фиксированы... Идею использовать для указателя на функцию уточнение, что он указывает на константный объект не понимаю - это лишь необходимо для предотвращения изменений объекта, на который ссылаемся (в общем случае... для embedded-случаев это еще указывает на то, что объект будет размещен в секции констант, расположенной в ROM). В случае, если объект, на который указывает указатель, - функция, то его и поменять то невозможно... Он в ROM расположен (если специально никаких усилий на то, чтобы разместить функцию в RAM, не предпринималось).... Да и зачем менять то? На ходу править код функции? P.S. Если я чего-то недопонимаю - надеюсь, мне тут объяснят
Сообщение отредактировал Student Pupkin - Aug 29 2009, 16:34
|
|
|
|
|
Aug 29 2009, 17:06
|
Частый гость
 
Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227

|
Цитата(Student Pupkin @ Aug 29 2009, 20:30)  Угумс  . ... Ну так может попробовать "возможно лишние" const убрать? А то как-то не по ANSI/ISO получается  ... Так уже пробовал, пока писал предыдущий пост - компилятор понимает и так и так... Но для порядку причесал. Цитата(Student Pupkin @ Aug 29 2009, 20:30)  А смысл? Если структура объявлена константой, то ее поля изменять нельзя... И потом - по логике константы должны размещаться в ROM. И еще сами функции размещаются в ROM, значит их адреса фиксированы... ...... Ну смысла не много - наверно для выразительности. Я в отрочестве не был сионистом  . Сначала строил структуру, далее инициализировал её указателями (адресами функций) - вот и поставил средний const (сами указатели ж у меня констанстные - хотя для функций это скорее всего само собой разумеющееся). Далее все это разместил в ПЗУ приписав первый const. Вот так и родил монстра  Но компилятор уживается с этим монстром. Меня ж более интересует последний монстр - "массив указателей на массивы указателей на структуры" (и это все в ПЗУ).
|
|
|
|
|
Aug 29 2009, 18:25
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 23-05-08
Пользователь №: 37 760

|
Цитата(cf7k @ Aug 29 2009, 21:06)  Меня ж более интересует последний монстр - "массив указателей на массивы указателей на структуры" (и это все в ПЗУ). Попробовал проделать аналогичное в Visual Studio 2008: CODE // Пустые функции (чтобы было) void func1(int a) { }; void func2(int a) { };
typedef struct { void (*func1)(int); void (*func2)(int); } PWInterface;
/* Здесь с помощью макроподстановки я определяю имя pConstPWInterfaceConst для константного указателя на структуру-константу PWInterface*/ #define pConstPWInterfaceConst const PWInterface *const
/* Таким способом не получается: typedef PWInterface *pPWInterface; */
const PWInterface PWMonitor1 = {func1, func2}; const PWInterface PWMonitor2 = {func2, func1};
pConstPWInterfaceConst PWMonitorPtr1 = &PWMonitor1; /* Таким способом не получается: 1)Ошибка компиляции (повторное использование const): const pPWInterface const PWMonitorPtr1 = &PWMonitor1; 2) Ошибка компиляции (несовместимость квалификаторов типов, т.е. указателю присваивается адрес константного объекта, чего нет в объявлении самого указателя): const pPWInterface PWMonitorPtr1 = &PWMonitor1; */ Мысли по этому поводу такие - Действительно, если писать что называется в лоб
Код const PWInterface *const PWMonitor1 = &PWMonitor1; то никаких ошибок - Если с помощью typedef определить имя pPWInterface для указателя на структуру PWInterface, то запись вида
Код const pPWInterface const PWMonitorPtr1 = &PWMonitor1; получится неверной. Видимо, подобная запись соответствует общей схеме объявления переменной - Код [класс памяти] [const] ТИП ИМЯ [инициализатор] Как видите, в этой схеме места для еще одного const нет. Вы можете только таким способом объявить указатель-константу (массив указателей-констант), но не можете сообщить, что это указатель на объект-константу (а способом в п.1 можете ) - Тоже самое происходит при попытке объявить массив указателей на указатели (есесно все там const - лень писать просто
) - Предлагаю писать в лоб (не вводите с помощью typedef имена "*pPWInterface" и "**ppPWInterface")
- Если не хотите в лоб, то воспользуйтесь define, как в моем куске (не знаю, как там насчет портируемости, эстетики, красоты и т.д., но такой способ работает, все компилится без ошибок и предупреждений). Там есесно упрощенно, но таким макаром можно и массив... И для указателя на указатель можно тоже аналогичный дефайн написать...
|
|
|
|
|
Aug 29 2009, 19:06
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(cf7k @ Aug 29 2009, 11:26)  Код const pPWInterface const PWMonMode1Arr[] = ... получаю warning: initialization discards qualifiers from pointer target typeВопрос первый: Что именно я недопонимаю? Хотел как лучше (чтоб через typedef... красившее. Вроде корректно определенный тип указателя при определении структуры)... Я сильно не вчитывался, но вот такое Код typedef struct { void (*FunctionPointer) (char Param); int (*OtherFuncPointer) (int SomeParam); }const PWInterface, *pPWInterface;
const PWInterface const PWMonitor0 = {0, 0}; const PWInterface const PWMonitor2 = {0, 0};
const pPWInterface const PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor2}; компилится без ворнингов. Добавил слово const в typedef.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 29 2009, 20:23
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 23-05-08
Пользователь №: 37 760

|
Цитата(AHTOXA @ Aug 29 2009, 23:06)  Я сильно не вчитывался, но вот такое Код typedef struct { void (*FunctionPointer) (char Param); int (*OtherFuncPointer) (int SomeParam); }const PWInterface, *pPWInterface;
const PWInterface const PWMonitor0 = {0, 0}; const PWInterface const PWMonitor2 = {0, 0};
const pPWInterface const PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor2}; компилится без ворнингов. Добавил слово const в typedef. А у меня такой варнинг Код warning C4114: same type qualifier used more than once Однако полагаю писать надо так: Код /* имя константной структуры PWInterface и указателя pPWInterface на константную структуру типа PWInterface */ typedef const struct { void (*FunctionPointer) (char Param); int (*OtherFuncPointer) (int SomeParam); } PWInterface, *pPWInterface;
/* Объявление константных структур типа PWInterface с именами PWMonitor0 и PWMonitor2*/ PWInterface PWMonitor0 = {0, 0}; // объявление константной структуры типа PWInterface PWInterface PWMonitor2 = {0, 0}; //
/* Объявление массива указателей-констант (на что указывает слово const) на структуру-константу типа PWInterface*/ const pPWInterface PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor2};
|
|
|
|
|
Aug 29 2009, 20:35
|
Частый гость
 
Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227

|
Цитата(AHTOXA @ Aug 29 2009, 23:06)  Я сильно не вчитывался, но вот такое ....... компилится без ворнингов. Добавил слово const в typedef. Гм... любопытный подход... возьму на заметку. Пасиба. Код вместо const PWInterface *const PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor0_c, &PWMonitor0_r}; получилось то что хотелось: const pPWInterface const PWMonMode1Arr[] = {&PWMonitor0, &PWMonitor2}; Но это "уровень 1" массива. Цитата(Student Pupkin @ Aug 29 2009, 22:25)  Попробовал проделать аналогичное в Visual Studio 2008: .... Мысли по этому поводу такие - Если не хотите в лоб, то воспользуйтесь define, как в моем куске (не знаю, как там насчет портируемости, эстетики, красоты и т.д., но такой способ работает, все компилится без ошибок и предупреждений). Там есесно упрощенно, но таким макаром можно и массив... И для указателя на указатель можно тоже аналогичный дефайн написать...
вот с дефайном не получилось - на самом деле я не define задаю, а пишу в лоб (ну что там вынести для красоты - это уже другое дело). Пока самый человеко понятный код у меня такой: Код const ppPWInterface const Pathways[] = {(ppPWInterface)(&PWMonMode1Arr), (ppPWInterface)(&PWMonMode2Arr), (ppPWInterface)(&PWMonMode2Arr)}; В общем-то и в объявлении есть двойной указатель и const'ы там где хочется... но... все же хочется знать, как это делается без коррекции типа, так сказать, по правилам языка.
|
|
|
|
|
Aug 29 2009, 21:06
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(cf7k @ Aug 30 2009, 02:35)  Гм... любопытный подход... возьму на заметку. Пасиба. Но это "уровень 1" массива. Со вторым уровнем всё проще. Имя массива является указателем на первый его элемент, потому не надо писать & в const ppPWInterface const Pathways[] = {&PWMonMode1Arr, &PWMonMode2Arr, &PWMonMode3Arr}; Короче, вот оба уровня, с учётом замечаний студента Пупкина: Код typedef struct { void (*FunctionPointer) (char Param); int (*OtherFuncPointer) (int SomeParam); }WInterface;
typedef WInterface const PWInterface; typedef PWInterface* const pPWInterface; typedef pPWInterface* const ppPWInterface;
const PWInterface PWMonitor0 = {0, 0}; const PWInterface PWMonitor2 = {0, 0};
const pPWInterface PWMonMode1Arr1[] = {&PWMonitor0, &PWMonitor2}; const pPWInterface PWMonMode1Arr2[] = {&PWMonitor0, &PWMonitor2, &PWMonitor0}; const pPWInterface PWMonMode1Arr3[] = {&PWMonitor2, &PWMonitor0};
const ppPWInterface final_array[] ={ PWMonMode1Arr1, PWMonMode1Arr2, PWMonMode1Arr3};
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 29 2009, 21:13
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 23-05-08
Пользователь №: 37 760

|
Ну а если так: Код /* Вводим тип структура-константа с именем PWInterface */ typedef const struct { void (*func1)(int); void (*func2)(int); } PWInterface;
/* Вводим тип указатель-константа на структуру-константу типа PWInterface с именем pPWInterface. */ typedef PWInterface *const pPWInterface;
/* Вводим тип указатель-константа на указатель-константу (типа pPWInterface) на структуру-константу типа PWInterface. Имя вводимого типа - ppPWInterface */ typedef pPWInterface *const ppPWInterface; Как такой вариант себя ведет? При этом конечно все const-ы из обявлений переменных нужно выкинуть. Т.е. не писать так: Код const PWInterface const PWMonitor0 = { &SomeFunc1, &SomeFunc2, .... }; ну и далее реализация этих функций. и так Код const pPWInterface const PWMonMode1Arr[] = ... А писать так: Код PWInterface PWMonitor0 = { &SomeFunc1, &SomeFunc2, .... }; . . . pPWInterface PWMonMode1Arr[] = ... Ну и понятно последний "рубеж" должен выглядеть так: Код ppPWInterface Pathways[] = {&PWMonMode1Arr, &PWMonMode2Arr, &PWMonMode3Arr}; То бишь без всяких const, т.к. момент с "константностью" уже определен в typedef. Не знаю точно почему, но ваш компилятор на лишние const не ругается, а вот Visual Studio выкидывает варнинг. Да и вообще считаю, что "добавлять лишние const для выразительности" - это попахивает нечистью какой-то  .
|
|
|
|
|
Aug 29 2009, 21:20
|
Частый гость
 
Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227

|
Цитата(Student Pupkin @ Aug 30 2009, 01:13)  То бишь без всяких const, т.к. момент с "константностью" уже определен в typedef. Не знаю точно почему, но ваш компилятор на лишние const не ругается, а вот Visual Studio выкидывает варнинг. Да и вообще считаю, что "добавлять лишние const для выразительности" - это попахивает нечистью какой-то  . Просто как-то не привык задавать "константный тип" (сегодня увидел такой подход впервые). Опять же привычно на месте определить - что в ПЗУ, что в ОЗУ, что не/изменяемо. А "наш"  компилятор сделан на основе GCC третьей версии. Цитата(Student Pupkin @ Aug 30 2009, 01:13)  Ну а с моим вариантом как? Ща... осваиваю... add: скорее всего придется доосвоить утром
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|