Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: модификатор const. Как правильно использовать в Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3
demiurg_spb
Цитата(sigmaN @ Jan 25 2018, 17:36) *
Если __ramfunc, то как раз все данные должны быть только в оперативке...
Например бутлоадер, который пишет во flash, не должен затрагивать данных из того-же flash.
Поэтому проще было убрать в приведённом примере слово static и слово const вовсе - результат был бы такой же, а буков меньше.
krux
IAR сделан не только под миниатюрные микроконтроллеры, а документация у него общая.
приведенный выше пример справедлив, например, когда есть тормозная флешка и быстрая и большая внешняя DDR. тогда cstartup как раз скопирует константу, к которой нужен быстрый и частый доступ в DDR.
DASM
Цитата(Quasar @ Jan 2 2018, 11:55) *
Я в свое время добавил вопрос о const в список вопросов для соискателей на собеседовании. Удивительно было то, что порой люди с опытом 5 лет и более, ничего кроме "const это константа неизменяемая" сказать не могут. А случай когда регистр периферии volatile const они обычно называют каким-то искусственным и притянутым за уши.

а он и есть приятнут за уши. Привидите плиз пример когда volatile const необходим и заоодно выдержку из стандарта где поведение этой конструкции описывается. Реально раздражают такие собеседователи с дебильными "что значит const char * const blavbla". Еще бы про auto спрашивали, который не впился ни в одно место эмеддерам ни в эпоху С, ни в эпоху С++ 14 когда он стал значить совершенно иное
sigmaN
Цитата
Правильно, потому что это __ramfunc и никто не хочет чтоб "Hello" занимало оперативку

Упс. Не заметил, что в примере локальные статики без const. Действительно hello будет в RAM, что действительно логично для __ramfunc.
demiurg_spb
Цитата(krux @ Jan 25 2018, 19:40) *
приведенный выше пример справедлив, например, когда есть тормозная флешка и быстрая и большая внешняя DDR. тогда cstartup как раз скопирует константу, к которой нужен быстрый и частый доступ в DDR.
В таких система обычно весь flash без разбора копируется в ОЗУ задолго да cstartup.
esaulenka
Цитата(DASM @ Jan 25 2018, 20:09) *
Еще бы про auto спрашивали, который не впился ни в одно место эмеддерам


Прошу заменять все Ваши сентенции "никому не нужен ..." на "мне не нужен".
Спасибо.
DASM
Цитата(esaulenka @ Jan 27 2018, 12:35) *
Прошу заменять все Ваши сентенции "никому не нужен ..." на "мне не нужен".
Спасибо.

хорошо, мне не нужен auto в С. Вам нужен?
Сергей Борщ
Не знаю, что он нынче делает в C, а в плюсах новый auto использую очень часто и нахожу очень удобным.
DASM
Цитата(Сергей Борщ @ Jan 27 2018, 23:24) *
Не знаю, что он нынче делает в C, а в плюсах новый auto использую очень часто и нахожу очень удобным.

Да, я про С имел в виду более. В С++ и const собственно гораздо важнее и нужнее. Просто само использование плюсов в эмбеддед ранее было сильно ограничено так сказать, свободно с STL стало писать можно относительно недавно, когда ОЗУ достаточно (256 К и более)
Quasar
Цитата
Привидите плиз пример когда volatile const необходим и заоодно выдержку из стандарта где поведение этой конструкции описывается.


Поведение volatile описано, поведение const тоже. Дерзайте, соединяйте вместе.

Участок одного из заголовочных файлов к STM32. Определение для __I и для __IO найдете сами. Хотя естественно можно с const не заморачиваться, также, как и с осмысленными именами функций, например.

Можно развить ваш вопрос: "приведите пример, когда const необходим и без него никак"?

Код
typedef struct
{
  __IO uint32_t POWER;          /*!< SDIO power control register,    Address offset: 0x00 */
  __IO uint32_t CLKCR;          /*!< SDI clock control register,     Address offset: 0x04 */
  __IO uint32_t ARG;            /*!< SDIO argument register,         Address offset: 0x08 */
  __IO uint32_t CMD;            /*!< SDIO command register,          Address offset: 0x0C */
  __I uint32_t  RESPCMD;        /*!< SDIO command response register, Address offset: 0x10 */
  __I uint32_t  RESP1;          /*!< SDIO response 1 register,       Address offset: 0x14 */
  __I uint32_t  RESP2;          /*!< SDIO response 2 register,       Address offset: 0x18 */
  __I uint32_t  RESP3;          /*!< SDIO response 3 register,       Address offset: 0x1C */
... etc

} SDIO_TypeDef;


Цитата(DASM @ Jan 25 2018, 20:09) *
а он и есть приятнут за уши.


А какие вопросы вы считаете не притянутыми за уши для программиста встроенных систем с опытом хотя бы более 5 лет?

Мне всегда интересно понять, как человек думает. Даже если умный человек столкнулся первый раз с такой конструкцией (а это вполне возможно), он задумается, постарается понять, о чем речь. Неумный начнет доказывать, разбрасывая слюни в разные стороны, что оно не надо, вы все тут идиоты, так никто не программирует! Но этот человек пришел к нам, решать наши задачи за деньги. Сейчас задача понять, что значит volatile const, вот и все.

Бывают и совсем волшебные кандидаты, которые даже вопрос не понимают, а пишут опыт 100500 лет и более.


Цитата(Сергей Борщ @ Jan 27 2018, 23:24) *
Не знаю, что он нынче делает в C, а в плюсах новый auto использую очень часто и нахожу очень удобным.


В C++ крайне нужная весчЬ.

Хотя в C++ я не использую это слово по старой привычке, и опираясь на логику некоторых местных товарищей, могу утверждать, что оно не нужно :-)
Arlleex
Ну, чтобы совсем подлить масла в огонь, можно вбросить "имя двумерного массива не есть указатель на указатель" и "имя массива и указатель это разные вещи".
Или, например, "константный указатель это не то же самое что указатель на константу"...
И действительно, есть люди которые в упор не видят разницу, когда она там есть.
DASM
Цитата(Arlleex @ Jan 28 2018, 20:09) *
Ну, чтобы совсем подлить масла в огонь, можно вбросить "имя двумерного массива не есть указатель на указатель" и "имя массива и указатель это разные вещи".
Или, например, "константный указатель это не то же самое что указатель на константу"...
И действительно, есть люди которые в упор не видят разницу, когда она там есть.

Ну указатель то как раз ясно, а вот с остальным так себе...
sigmaN
Код
int arr[2] = {0, 1};
int i;
int pi;

int *ptr = arr;
int ptri;

int main(void)
{
    i = arr[1];
    pi = *arr+1;
    ptri = ptr[1];
    if( (i == pi) == ptri )
        asm("nop");
    /* Replace with your application code */
    while (1)
    {
    }
}

Для затравки кусок кода:
Брэйкпоинт установленный на nop сработает? Сработает. Значит массив это указатель? А указатель это массив? wink.gif

На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот.

Кто ответит? )
gerber
Цитата(sigmaN @ Jan 28 2018, 22:50) *
Брэйкпоинт установленный на nop сработает? Сработает.

Не сработает.
DASM
Цитата(gerber @ Jan 28 2018, 23:03) *
Не сработает.

Сработает!
Только вот за конструкции видаif ((i == pi) == ptri) лучше отрубать голову голову сразу. Такой код гораздо хуже случая, когда программер не разбирается в const volatile
Гм, а как эта строка вообще работает то ?
http://www.includehelp.com/c/how-expressio...rogramming.aspx


Гыыы int arr[2] = { 0, 1 }; Ай маладца, а если nt arr[2] = { 0, 2 }; ?
Не, реально 10 лет без права переписки за такие хаки
The result of (a==cool.gif is 1 (i.e. true). И еще - по стандарту true совсем не обязан быть 1

Строка сравнивает числовое значение true , обычно 1, со значением из массива по первому индексу... глубокомысленно
sigmaN
Я думаю стоит сконцентрироваться на работе с массивом и индексами, сравнением массива с указателями.

Ответа на вполне конкретный вопрос пока не поступило.
Цитата
На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот.
Quasar
Цитата(sigmaN @ Jan 28 2018, 23:51) *
Ответа на вполне конкретный вопрос пока не поступило.


sizeof ( ptr ) != sizeof ( arr )

biggrin.gif
alx.bilous
Цитата(sigmaN @ Jan 28 2018, 22:50) *
На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот.

https://ideone.com/SLqzMw
DASM
Ну имя массива это не lvalue , нельзя записать "имя_массива++" например. А указатель - lvalue

Цитата(alx.bilous @ Jan 29 2018, 00:31) *

prog.c:8:4: error: assignment to expression with array type
a = b;
VS дает на такое именно " error C2106: '=' : left operand must be l-value"

Цитата(sigmaN @ Jan 28 2018, 23:51) *
Я думаю стоит сконцентрироваться на работе с массивом и индексами, сравнением массива с указателями.

Ответа на вполне конкретный вопрос пока не поступило.

Так а кусок кода что Вы привели - какой смысл имеет и какое отношение к этому? Он попросту ошибочен
alx.bilous
Мне и правда нужно было упоминать что строка девять и строка восемь это тот случай когда "массив поведет себя иначе чем указатель"?
Arlleex
Цитата
На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот.

Кто ответит? )

Я отвечу. Ознакомьтесь. laughing.gif
sidy
Цитата(Quasar @ Jan 28 2018, 12:14) *
В C++ крайне нужная весчЬ.

Хотя в C++ я не использую это слово по старой привычке, и опираясь на логику некоторых местных товарищей, могу утверждать, что оно не нужно :-)

Очень нужная весчЬ - использовать я ее конечно не буду rolleyes.gif
_Sam_
Цитата
в первом варианте в глобальной константе
этот массив помещен в память Flash. Правильное поведение.

Во втором варианте в стек - неправильное
в третьем варианте во Flash память.


По сути первый и третий вариант в вашем случае идентичны и отличаются они только областью видимости, поэтому логично, что один и тот же компилятор делает в этих вариантах одно и то же. Второй вариант отличается тем, что массив живет только во время вызова функции, поэтому запихивать его пожизненно во флэш нелогично.

Цитата
На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот.

К имени массива привязан не только адрес, но и размер. Как уже писали выше размеры массива и указателя не равны.
Код
#include <iostream>
using namespace std;
uint32_t na[] = {0,1};
uint32_t *a = na;

int main() {
    if(sizeof(a) == sizeof(na))
       cout << "equal";
    else
       cout << "not equal";
    // your code goes here
    return 0;
}


Еще пример когда в качестве параметра передается ссылка на массив, в этом случае указатель в качестве параметра не пройдет.
Цитата
void func(uint32_t (&na)[2])



Kabdim
Цитата(sigmaN @ Jan 28 2018, 22:50) *
Кто ответит? )

Даже зная как найти ответ всегда хотелось настучать по голове непризнанным гениям ставящим это и подобное на собеседовании. Ну и уж точно не пошел бы контору где такие вопросы задают.
juvf
Цитата(_Sam_ @ Jan 29 2018, 12:45) *
Второй вариант отличается тем, что массив живет только во время вызова функции, поэтому запихивать его пожизненно во флэш нелогично.
Он в любом случае пожизненно живет во флеш... до вызова функции он живет только во флеш, во время вызова живет и в ОЗУ и во флеш.
ViKo
Цитата(juvf @ Jan 29 2018, 12:14) *
Он в любом случае пожизненно живет во флеш... до вызова функции он живет только во флеш, во время вызова живет и в ОЗУ и во флеш.

Во флэш он не живет, а существует хранится. laughing.gif
DASM
Цитата(Kabdim @ Jan 29 2018, 11:19) *
Даже зная как найти ответ всегда хотелось настучать по голове непризнанным гениям ставящим это и подобное на собеседовании. Ну и уж точно не пошел бы контору где такие вопросы задают.

+++! А какой у них при этом умный вид! Как правило это всякие КТН, с напускным видом умудренного опытом жирного кота. Если посмотреть потом их код - как правило это академическая муть с неочевидной перегрузкой операторов, неуклюжей попыткой засунуть ООП там, где оно вообще не надо итп. Реально полезного - ноль, собственно поэтому и ищут людей ))
Правда это не случай Сигмы - тут обратное , код похож на тот, что напишет бывший ассемблирщик, которому дали С. Причем с ошибкой (или это тест на внимание такой? )
sigmaN
Код
int (*ptr)[2];

Скомпилится?
ptr это массив поинтеров?
Поинтер на массив?
Ваш варинт ответа wink.gif
DASM
Цитата(sigmaN @ Jan 29 2018, 18:46) *
Код
int (*ptr)[2];

Скомпилится?
ptr это массив поинтеров?
Поинтер на массив?
Ваш варинт ответа wink.gif

это вот что https://www.youtube.com/watch?v=cdX8r3ZSzN4 sm.gif
А так то - указатель на массив, только вот по-моему редко кто такими конструкциями пользуется.
juvf
Цитата(ViKo @ Jan 29 2018, 17:21) *
Во флэш он не живет, а существует хранится. laughing.gif
для эстетов
Он в любом случае пожизненно хранится (занимает память) во флеш... до вызова функции он храниться (занимает память) во флеш, во время вызова хранится (занимает память) и в ОЗУ и во флеш.laughing.gif
DASM
delete
Arlleex
Цитата(sigmaN @ Jan 29 2018, 18:46) *
Код
int (*ptr)[2];

Скомпилится?
ptr это массив поинтеров?
Поинтер на массив?
Ваш варинт ответа wink.gif

Указатель на массив.

Теперь моя очередь =)

Код
char (*(*func(void))[3])(void);

Цитата
Скомпилится?
Ваш варинт ответа wink.gif

biggrin.gif
sigmaN
А вот это я расшифровать пока не могу blink.gif

Озвучу мысли, но я не уверен что это правильно
func это массив указателей на функцию без параметров, которая возвращает указатель на фукнцию без параметров, которая возвращает char
Arlleex
Цитата(sigmaN @ Jan 30 2018, 00:07) *
А вот это я расшифровать пока не могу blink.gif

Озвучу мысли, но я не уверен что это правильно
func это массив указателей на функцию без параметров, которая возвращает указатель на фукнцию без параметров, которая возвращает char

Ну, я Вас понимаю =)
Подобные "сюрпризы" ни раз приходилось наблюдать в индусских говнопрограммах драйверах для процессоров различных платформ.
Пример надуманный, и у вышеупомянутых коллек по ремеслу индусских товарищей было что-то чуть-чуть попроще, но лишь чуть-чуть laughing.gif
P.S. func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров.

Кстати, кто там хотел проверять кандидатов на знание языка Си - да элементарно предложите написать окружение для безошибочного компилирования следующей белиберды
Код
for(;P("\\n"),R-;P("|"))for(e=C;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);

Этой строке лет 20 уже - как гласит легенда - "первоапрельская шутка для UNIX-программистов" раньше была...
Это покажет уровень понимания (!) языка в принципе. Я знаю, что знание языка отнюдь не всегда самое важное, однако эмбеддерам мое мнение нахрен никому не нужно считаю нужно уметь "думать" на языке, на котором пишешь.
DASM
Цитата(Arlleex @ Jan 30 2018, 00:14) *
Ну, я Вас понимаю =)
Подобные "сюрпризы" ни раз приходилось наблюдать в индусских говнопрограммах драйверах для процессоров различных платформ.
Пример надуманный, и у вышеупомянутых коллек по ремеслу индусских товарищей было что-то чуть-чуть попроще, но лишь чуть-чуть laughing.gif
P.S. func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров.

Ну блин, я к Вам в кино в следущий раз подсяду и буду шептать "а убийца то - дворник. " Только я тоже пока не могу корректно компилящийся код под такую конструкцию написать, даже после такого ответа. Возникает идея - давать на собеседовании такие вот вопросы, и, если решил - не брать ни в коем случае, а то весь код в таком ключе и будет написан. Шарады и ребусы это конечно круто, но не в рабочем коде. А вообще это все ерунда я считаю. Пусть не знает вообще ни одного языка, но нарисует мне удобные интерфейсы - это супер. Я вот уже месяц торможу над проектом, при этом основной инструмент - планшет с пером, рисую взаимосвязи и интерфейсы, вот там реально мало чую у меня опыта. А эти шарады нафик не сдались
"понимания (!) языка в принципе." - ничего кроме знания формальных правил это не покажет. Давайте ужо кодера от программиста отличать что-ли
Задумался "нужно уметь "думать" на языке" - а чтобы думать всегда надо думать словами ? Двуязычные тут есть? На каком языке думаете обычно? Я про реальные языки, типа русского там или украинского, английского.
Arlleex
Цитата(DASM @ Jan 30 2018, 00:20) *
Ну блин, я к Вам в кино в следущий раз подсяду и буду шептать "а убийца то - дворник. " Только я тоже пока не могу корректно компилящийся код под такую конструкцию написать, даже после такого ответа. Возникает идея - давать на собеседовании такие вот вопросы, и, если решил - не брать ни в коем случае, а то весь код в таком ключе и будет написан. Шарады и ребусы это конечно круто, но не в рабочем коде. А вообще это все ерунда я считаю. Пусть не знает вообще ни одного языка, но нарисует мне удобные интерфейсы - это супер. Я вот уже месяц торможу над проектом, при этом основной инструмент - планшет с пером, рисую взаимосвязи и интерфейсы, вот там реально мало чую у меня опыта. А эти шарады нафик не сдались

Вам лично могу придумать полдесятка витиеватых примеров для решения rolleyes.gif

Согласен, запутанные конструкции реально использовать трудно. Но менее сложные, такие как массивы указателей на функции, использовать приходилось, да и решение выглядело вполне изящно.

Многие "фишки" C++ как раз раскрываются вот такими интересными конструкциями... Тот же механизм виртуальных функций...
sigmaN
Цитата
func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров.
А, точно. Немного запутался
DASM
Цитата(Arlleex @ Jan 30 2018, 00:27) *
Вам лично могу придумать полдесятка витиеватых примеров для решения rolleyes.gif

Согласен, запутанные конструкции реально использовать трудно. Но менее сложные, такие как массивы указателей на функции, использовать приходилось, да и решение выглядело вполне изящно.

Многие "фишки" C++ как раз раскрываются вот такими интересными конструкциями... Тот же механизм виртуальных функций...

Вот после такой хрени таки да, auto как глоток воздуха становится. Ловлю себя на мысли, что то , чем не пользуешься - забывается мгновенно. Я синтаксис того что Вы написали однозначно не прочел бы ни с первого ни второго раза. В реальной работе крайне редко использую даже простой указатель на функцию. Если нужен - снова гуглю - где там скобочки и звездочки правильно расставить надо. Честно говоря такая моя "безграмотность" - не мешает. Проектирование программы, повторюсь, считаю куда более сложной задачей, чем собственно претворение готового проекта в код
"использовать приходилось, да и решение выглядело вполне изящно" - да, согласен. Но я такие конструкции с гуглом пишу а не по памяти, обычно их пару раз в моих небольших проектах то и нужно всего использовать.
Arlleex
Цитата(DASM @ Jan 30 2018, 00:34) *
Вот после такой хрени таки да, auto как глоток воздуха становится. Ловлю себя на мысли, что то , чем не пользуешься - забывается мгновенно. Я синтаксис того что Вы написали однозначно не прочел бы ни с первого ни второго раза...
Честно говоря такая моя "безграмотность" - не мешает. Проектирование программы, повторюсь, считаю куда более сложной задачей, чем собственно претворение готового проекта в код...

Насчет проектирования программы с Вами полностью согласен.
Я просто люблю разные "трюки" в Си. Но стараюсь их избегать в реальном применении, потому как понимаю, что мой код, возможно, кому-то еще и поддерживать.
DASM
"кому-то еще и поддерживать." и 99 % это вы сами и будете, чертыхаясь и пытаясь понять свой же код. Я - за хорошие названия переменных и методов, вот тут тоже думать много надо над именем, (хотя собственно эти имена и отражают стадию проектирования). И если они хорошие - методы не нуждаются в комментариях (самодокометированный код_) за редким исключением. Еще думать как лучше вернуть несколько значений, раньше я передавал указатели, которые метод заполнял. Сейчас чаще завожу структуру отдельную и возращаю ее. Если структура выглядит как смесь совершенно несвязанных вещей - значит и метод у меня неправильный задуман, и его надо разбивать на несколько мелких более. В общем чем больше пишу, тем более простой код стараюсь делать, избегаю сложных конструкций в одну строку (зачем ? хвастать что можешь так ? перед самим собой что-ли?). Не стеснятся goto в меру . Лучше написать "туповатый" код но понятный даже новичку в С, чем вычурную констркцию if( (i == pi) == ptri ) и не заметить что первая ее часть возращает bool который ты ошибочно сравниваешь с int и это работает.. если int равен 1 и только.. как-то так.. а уж какие горы в ++ можно навернуть то это жуть. Страуструп признавался, что знает С++ где-то на 80..90 из 100. Куда уж смертным то
ViKo
Мудреные конструкции наподобие вышеприведенных разбираются в учебнике K&R "Язык C", там и метод описан. В жизни мне использовать нет необходимости.
dxp
Цитата(Arlleex @ Jan 30 2018, 04:14) *
P.S. func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров.

func - не функция, а указатель на функцию.
Quasar
Цитата(DASM @ Jan 29 2018, 18:04) *
+++! А какой у них при этом умный вид! Как правило это всякие КТН, с напускным видом умудренного опытом жирного кота. Если посмотреть потом их код - как правило это академическая муть с неочевидной перегрузкой операторов, неуклюжей попыткой засунуть ООП там, где оно вообще не надо итп. Реально полезного - ноль, собственно поэтому и ищут людей ))


Стоит заметить, что ваши личные комплексы не являются темой данного обсуждения. Если у вас есть какие-то жизненные упущения, как то неполученный статус КТН, например, можете завести отдельную тему, где поплачитесь, а мы вас подбодрим добрым словом.

biggrin.gif
DASM
"поплачИтесь" ,- непременно

Цитата(dxp @ Jan 30 2018, 08:14) *
func - не функция, а указатель на функцию.

Совсем ничего не соображаю, а почему такая запись возможно тогда?
CODE
char(*(*func(void))[3])(void)
{
char(*(*f)[3]) (void) = NULL;
return f;
}
Arlleex
Цитата(dxp @ Jan 30 2018, 08:14) *
func - не функция, а указатель на функцию.

Вы не правы.

Цитата
Совсем ничего не соображаю, а почему такая запись возможно тогда?
CODE
char(*(*func(void))[3])(void)
{
char(*(*f)[3]) (void) = NULL;
return f;
}

Потому что func - это то, что я писал выше. А вот f - это указатель на массив указателей на функции. Записи логически и синтаксически корректны.
Quasar
Цитата(DASM @ Jan 30 2018, 09:04) *
"поплачИтесь" ,- непременно


Ваше замечание притянуто за уши. Поскольку Я применяю это слово редко (или не применяю вовсе), могу делать в нем столько ошибок, сколько захочу. Я же не яйцеголовый КТН в самом деле! И если меня кто-то на собеседовании поправит, обязательно настучу по голове, как было предложено выше.
DASM
Цитата(Arlleex @ Jan 30 2018, 09:37) *
логически и синтаксически корректны.

жаль что совершенно нечитаемы (мне). Всегда удивляют (приятно) люди (на Хабре например) которые это щелкают как орехи. Не понимаю, как при обычном программировании можно получить опыт чтения такого.
dxp
Цитата(Arlleex @ Jan 30 2018, 13:37) *
Вы не правы.

char (*(*func(void))[3])(void);

да, не указатель (проглядел скобки справа), но это и не функция. sm.gif Строго говоря, func - есть имя функции, которое семантически является её адресом, т.е. технически это указатель. Всё выражение да, не указатель, но, строго, и не функция.
Quasar
Цитата(Arlleex @ Jan 30 2018, 00:14) *
P.S. func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров.


Припомнил у себя в проекте такой же код, правда только после того, как вы на русском дали разъяснение по своему примеру. Там все было сделано через typedef и по сути даже более сложная структура была.

Мое мнение, подобная бадяга (указатель, на указатель на функцию возвращающую массив указателей тра-ля-ля...) может применятся очень часто, вопрос только в том, как оно оформлено.

Код
typedef int32_t /*successful = 0*/ ( *callback_func_t ) ( uint32_t /*protocol status*/ );

typedef callback_func_t callback_tbl_t[LAST_CALLBACK_ID];

typedef struct {
    uint32_t id;
    callback_tbl_t cl_tbl;  
} proto_impl_t;

static proto_impl_t impl[MAX_NOF_IMPLS] = { 0 };

callback_tbl_t *impl_get_callbacks ( uint32_t impl_id ) {

    for ( uint32_t i = 0; i < MAX_NOF_IMPLS; i++ ) {
        if ( impl[i].id == impl_id ) {
            return &impl[i].cl_tbl;
        }
    }

    int32_t ( *(*f)[32] ) (uint32_t) = NULL;    /* Это я уже сейчас добавил, проверить ругнется ли компилятор. Не ругается. */

    return f;
}
Arlleex
Цитата(dxp @ Jan 30 2018, 12:08) *
char (*(*func(void))[3])(void);

да, не указатель (проглядел скобки справа), но это и не функция. sm.gif Строго говоря, func - есть имя функции, которое семантически является её адресом, т.е. технически это указатель. Всё выражение да, не указатель, но, строго, и не функция.

Технически любое имя функции - это есть указатель. Даже
Код
void f1(void);

Согласно Вашей логике, f1 - не функция? Стандартописатели из комитета ANSI C ошиблись с терминологией? rolleyes.gif
Все выражение, все-таки - функция... Вернее, ее прототип.
Код
char (*(*func(void))[3])(void)
{
  ...
}

Технически, синтаксически, логически, семантически (что там еще?) - это именно функция. Я могу ее вызвать, потому что это функция. Я не могу присвоить func ничего, потму что это не указатель, а идентификатор, связанный с выделенным участком кода.

Вот небольшой пример
Код
// ôóíêöèÿ, âîçâðàùàþùàÿ óêàçàòåëü íà ìàññèâ óêàçàòåëåé íà ôóíêöèè, âîçâðàùàþùèå char

#include <stdio.h>

char func1(void) {printf("I am func1\n"); return 1;}
char func2(void) {printf("I am func2\n"); return 2;}
char func3(void) {printf("I am func3\n"); return 3;}

char (*MassFunc[3])(void) = {func1, func2, func3};

char (*(*func(void))[3])(void)
{
    return &MassFunc;
}

int main(void)
{
    int *pFunc = (int *)func();
    
    for(int i = 0; i < 3; ++i)
       (*(char (*)())pFunc[i])(); // в С указатели на функции не индексируются, поэтому используется промежуточный указатель на int
    
    while(1);
}



Важное замечание №1: если все-таки придется использовать какую-то гибкую схему вызовов - лучше, как и было озвучено Quasar, через typedef.
Важное замечание №2: не пишите так никогда (как в примере выше у меня). Это всего лишь пример, но никак не побуждение к действиям. Если и хочется сделать что-то гибко и структурно - лучше тщательно продумать концепцию кода и оформить с typedef-ами (иначе Вас потом будут проклинать biggrin.gif ).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.