|
модификатор const. Как правильно использовать в Си |
|
|
|
Dec 22 2017, 15:39
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
где компилятор должен расположить "переменные" такого вида: CODE // Описано глобально const u8 x_pos[][8] = { {50, 60}, {55, 62, 69, 76, 83, 90, 97, 104}, {76}, {76}, }; то же самое, описано внутри функции и то же самое внутри функции CODE static const u8 x_pos[][8] = { {50, 60}, {55, 62, 69, 76, 83, 90, 97, 104}, {76}, {76}, };
у меня есть неизменяемый массив большого размера и при входе в функцию этот констатный масив создается в стеке. если его не определить как static правильно ли это поведение или нет? в первом варианте в глобальной константе этот массив помещен в память Flash. Правильное поведение. Во втором варианте в стек - неправильное в третьем варианте во Flash память.
|
|
|
|
|
 |
Ответов
(1 - 99)
|
Dec 22 2017, 16:29
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(inventor @ Dec 22 2017, 19:21)  может ли компилятор поместить static const не во flash а в памяти данных? Легко. Причём это поведение описано в стандарте. Если у флэша и ОЗУ разные адресные пространства именно так и будет. Например, для AVR специально придуман квалификатор __flash, который укажет компилятору, что данные нужно поместить во флэш, а не в основную память (коей считается ОЗУ). Для ARM, где единое адресное пространство, можно с уверенностью сказать, что static const данные лягут во флэш (кроме случая когда компилятор решит соптимизировать) . Умная книга, которую ТС советовали читать - это стандарт языка Си...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 22 2017, 17:00
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата(inventor @ Dec 22 2017, 19:21)  может ли компилятор поместить static const не во flash а в памяти данных? Теоретически может, но делать этого не будет, т.к. поведение задано настройками. Если говорить за gcc, то где-то в недрах проекта у вас должен быть файл с расширением *.ld в котором записано что и куда класть. Вы можете его редактировать что бы получить результат отличный от того того что по умолчанию. Цитата(Raven @ Dec 22 2017, 19:53)  А разве не должен компилятор помещать глобальные и static const объекты в .rodata секцию? (которая естественным образом ассоциируется с FLASH) А линкер может в соответствии со своим скриптом секцию запихнуть туда куда записано в скрипте.
|
|
|
|
|
Dec 22 2017, 17:07
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Kabdim @ Dec 22 2017, 20:00)  Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё. А куда они лягут - об этом более нет ни слова. Кстати, задумайтесь над тем что будет если константные данные всегда будут лежать во флэш и чем это чревато для архитектуры AVR и не только... Совершенно легальный код станет невозможен: Код char str1[] = "xxx"; const char str2[] = "yyyy";
extern void print_str(const char* str);
print_str(str1); // норм print_str(str2); // попа Или так будет делать бессмысленно: Код volatite const int uptime; Это я к чему - крутить параметры в скриптах линкера надо не с шашой наголо, а очень и очень вдумчиво...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 23 2017, 12:07
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Raven @ Dec 22 2017, 19:53)  А разве не должен компилятор помещать глобальные и static const объекты в .rodata секцию? (которая естественным образом ассоциируется с FLASH) Я сразу себя приучил, что компилятор мне ничего не "должен"  Особенно в части, если включена оптимизация. И даже если не включена. Есть много платформо-зависимых ньюансов. Разобраться, опятьже, помогает RTFM + работа в отладчике с memory-->View.
|
|
|
|
|
Dec 23 2017, 18:03
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
то есть для того что бы константные данные легли во flash память необходимо сделать typedef для такого типа: CODE typedef const unsigned char cu8; #define scu8 static cu8
|
|
|
|
|
Dec 23 2017, 19:41
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата(demiurg_spb @ Dec 22 2017, 20:07)  Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё. Верно, но пост был про поведение компилятора, а раздел для новичков, так что ответ по дефолту шел про армы о чем свидетельствуют некоторые ответы ТСа. Об особенностях авров честно говоря задумываться не хочу, в 2017 труп уже пора закопать.
|
|
|
|
|
Dec 24 2017, 17:36
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(demiurg_spb @ Dec 22 2017, 22:07)  Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё. Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство. ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры. Куда разместит - зависит от компилятора. А вообще мне тоже не понятно почему во 2-м случае в ОЗУ. Получается что эти данный размещены дважды - и в озу и в пзу. Если это авр - то это понятно, для авр все случаи должны быть в озу. Если арм - то вроде как все константы должны быть в флеше. Зачем их дублировать в ОЗУ?
|
|
|
|
|
Dec 24 2017, 19:04
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(juvf @ Dec 24 2017, 20:36)  Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство.
ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры.
Куда разместит - зависит от компилятора. А вообще мне тоже не понятно почему во 2-м случае в ОЗУ. Получается что эти данный размещены дважды - и в озу и в пзу. Если это авр - то это понятно, для авр все случаи должны быть в озу. Если арм - то вроде как все константы должны быть в флеше. Зачем их дублировать в ОЗУ? хотя бы потому, что ICode и Dcode шины разные, мультплексируются. При выборке из флеша медленого к тому же prefetch работает, размещая константы во флеше он сбросится, итого двойной тормоз выйдет. const нужен только чтобы уберечь программиста от самого себя, а никак не указание компилятору что и как размещать.
Эскизы прикрепленных изображений
|
|
|
|
|
Dec 25 2017, 03:10
|
Участник

Группа: Участник
Сообщений: 52
Регистрация: 5-05-17
Пользователь №: 96 902

|
Цитата(DASM @ Dec 24 2017, 20:04)  const нужен только чтобы уберечь программиста от самого себя, а никак не указание компилятору что и как размещать. А почему глобальный конст во флеше, локальный в озу?
Сообщение отредактировал razrab83 - Dec 25 2017, 03:16
|
|
|
|
|
Dec 25 2017, 07:57
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(DASM @ Dec 25 2017, 12:28)  еще как указание. статик в теле фции размещается не на стеке, а в общей куче (не путать с кучей malloc). пф.... утверждение осталось, только дополню... Более того, static - это всего лишь указание компилятору, что данные статические, а никак не указание компилятору что и как размещать, я имел в виду, указание не про кучу и стек, а указание про озу/флешь/еепром/внешнюю память и т.п. Цитата это самодеятельность компилера на его страх и риск. Согласен. В Си/С++ нет ни каких указаний на этот счет. Поэтому разработчики компиляторов на своё усмотрение делают реализацию. И поэтому, если важна область размещения, нужно компиллер контролировать и давать явные указания для размещения данных в нужную память. Цитата(DASM @ Dec 25 2017, 12:31)  А уж размещение статик не на стеке - прросто вытекает из этого Ни чего не вытекает. Статик можно разместить в ОЗУ, а можно разместить в флеше. Конст можно разместить в озу, а можно в флеше. Компилятор волен сам - где и что размещать (в озу или во флешь), и его размещения не поддаются логике.
|
|
|
|
|
Dec 25 2017, 08:15
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(juvf @ Dec 25 2017, 10:57)  пф.... утверждение осталось, только дополню...
Более того, static - это всего лишь указание компилятору, что данные статические, а никак не указание компилятору что и как размещать, я имел в виду, указание не про кучу и стек, а указание про озу/флешь/еепром/внешнюю память и т.п.
Согласен. В Си/С++ нет ни каких указаний на этот счет. Поэтому разработчики компиляторов на своё усмотрение делают реализацию. И поэтому, если важна область размещения, нужно компиллер контролировать и давать явные указания для размещения данных в нужную память.
Ни чего не вытекает. Статик можно разместить в ОЗУ, а можно разместить в флеше. Конст можно разместить в озу, а можно в флеше. Компилятор волен сам - где и что размещать (в озу или во флешь), и его размещения не поддаются логике. вытекает что не на стеке
|
|
|
|
|
Dec 25 2017, 14:08
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(juvf @ Dec 24 2017, 20:36)  Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство.
ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры. Если Вы не в теме, то это не означает, что этого нет. https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gc...-Address-SpacesВ настоящий момент в GCC именно на этой почве случился ступор. Разработчики avr-gcc не могут сделать так, чтобы по возможности константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает. Если интересно - скачайте стандарт c11.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 25 2017, 14:53
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Сергей Борщ @ Dec 25 2017, 17:48)  Я не про плюсы и говорю. И ступор не в плюсах. Код const char __flash* const __flash names[] = { "aaa", "bbb", "ccc" }; не работает, а по всей здравой логике должно. но народ упёрся и говорит, что нарушать стандарт не будем.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 25 2017, 16:12
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
Цитата(Сергей Борщ @ Dec 25 2017, 17:48)  А еще - бывают контроллеры вообще без набортного флеша, там и код и константы - все в ОЗУ живет. И к чему все эти споры? cc3200 но там все равно подрузамевается память только для чтения: CODE 45 190 bytes of readonly code memory 6 072 bytes of readonly data memory 138 267 bytes of readwrite data memory
|
|
|
|
|
Dec 25 2017, 16:28
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё. Цитата(demiurg_spb @ Dec 25 2017, 19:08)  Если Вы не в теме, то это не означает, что этого нет. https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gc...-Address-SpacesВ настоящий момент в GCC именно на этой почве случился ступор. Разработчики avr-gcc не могут сделать так, чтобы по возможности константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает. Если интересно - скачайте стандарт c11. И? Где в стандарте си основное адресное пространство? Да даже в по вашей ссылке нет ни каких основных адресных пространств. ps Это вы не в теме. При чем тут на какойт-о AVR Named Address Spaces? Вопрос не о авр, и даже не о gcc, а о Си. pps Цитата константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает. Навыдумывали. В стандарте Си нет даже слова flash. Если интересно - скачайте стандарт c11.
|
|
|
|
|
Dec 26 2017, 12:03
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
С вами бесполезно разговаривать - это Вы к AVR и flash привязались, не удосужившись прочесть представленные ссылки. Всё о чём я написал напрямую относится к GCC в общем который, если Вы не в курсе, раньше всех коммерческих продуктов реализует новые возможности языка. Мы используем в своих разработках GCC для множества архитектур, и по мере возможности делаем его и libc лучше. И мне очень странно слушать Ваши непонятные высказывания. На этом с Вами разговор считаю законченным, пребывайте в осознании своего всезнания и далее. Цитата As an extension, GNU C supports named address spaces as defined in the N1275 draft of ISO/IEC DTR 18037. Support for named address spaces in GCC will evolve as the draft technical report changes. Calling conventions for any target might also change. At present, only the AVR, SPU, M32C, RL78, and x86 targets support address spaces other than the generic address space.
Address space identifiers may be used exactly like any other C type qualifier (e.g., const or volatile). See the N1275 document for more details. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1275.pdfhttp://www.open-std.org/jtc1/sc22/wg14/www/docs/n1005.pdfВдогонку: OpenCL основан на С99 и тоже использует схожие принципы что и Си для ембеда в части адресных пространств. https://software.intel.com/en-us/articles/t...ce-in-opencl-20
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 27 2017, 02:57
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(demiurg_spb @ Dec 26 2017, 17:03)  написал всё что думаю о вас.... много букв.... удалил.... Вы видите/замечаете/понимаете разницу между "общий" и "основной", между " generic" и " general", между " Programming languages - C" и " Programming languages - C - Extensions to support embedded processors", между "gcc" и "си". Цитата принципы что и Си для ембеда Ого!!! Уже не "Си", а "Си для ембеда". Исправляетесь, значит есть смысл от общения.
|
|
|
|
|
Dec 27 2017, 10:12
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(juvf @ Dec 27 2017, 05:57)  Пусть generic - общий. Что от это изменилось? Си он и в африке Си и теперь в нём есть часть (читай глава) затрагивающая ембед. А на gcc я ссылаюсь от того что это чуть-ли не единственный (ну может быть clang ещё) доступный, открытый и ОЧЕНЬ распространнённый компилятор для огромного количества архитектур. Люди, разрабатывающие его являются членами комитета, утверждающего и разрабатывающего стандарт Си. Чем не автортет? Не согласны - приведите свои доводы. Не нравится как я излагаю - читайте прикреплённые мной ссылки на оригиналы статей. Ради этого я их и прилагаю.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 27 2017, 15:14
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 25-07-17
Пользователь №: 98 462

|
Вставлю и я свои 5 коп. Inventor, всегда можно посмотреть адрес конкретной переменной. Или константы . Средства Си это отлично могут делать.
|
|
|
|
|
Dec 27 2017, 16:08
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(inventor @ Dec 25 2017, 10:36)  ....в сегодняшних компиляторах для этого нужно писать в заголовке перменнные с словом extern
слово global помогло бы этого избежать По количеству нажатий global ничем не лучше extern. Зачем плодить синонимы?
|
|
|
|
|
Jan 3 2018, 10:26
|
Участник

Группа: Участник
Сообщений: 52
Регистрация: 5-05-17
Пользователь №: 96 902

|
Цитата(Quasar @ Dec 30 2017, 09:04)  Локальная const переменная может инициализироваться в момент вызова функции и на стадии сборки неизвестна. Нечего класть во флеш. А вот static const и глобальная const переменная известны уже на стадии сборки. Локальная const переменная на стадии сборки известна.
|
|
|
|
|
Jan 3 2018, 10:53
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Код int f(int a ) { const int c = 5; return a + c; } Цитата Локальная const переменная на стадии сборки известна. Сделали такой вывод потому, что можете видеть = 5 своими глазами? Выразимся точнее Переменная c при любой настройке компилятора не ляжет во флеш потому, что у нее не static storage duration. Переменная c вообще не займет никакой памяти(даже на стеке) при включении оптимизации. Ознакомьтесь с https://en.wikipedia.org/wiki/Constant_folding
--------------------
The truth is out there...
|
|
|
|
|
Jan 3 2018, 13:47
|
Участник

Группа: Участник
Сообщений: 52
Регистрация: 5-05-17
Пользователь №: 96 902

|
Цитата Переменная c вообще не займет никакой памяти(даже на стеке) Как раз таки переменная c займет память программ. int f(int a ) {//при входе а копируем в аккумулятор const int c = 5;//этой строки в коде вообще может не быть. return a + c;//здесь будет выполнен может быть выполнен код типа такого add acc,#5, где #5 - это и есть наша const int c, и эта пятерка лежит во флешь. }
|
|
|
|
|
Jan 3 2018, 18:26
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Ну так мы же про размещение данных говорим вроде как. Цитата return a + c;//здесь будет выполнен может быть выполнен код типа такого add acc,#5, где #5 - это и есть наша const int c, и эта пятерка лежит во флешь. Кстати говоря эта пятерка уже не переменная. Она станет частью инструкции в общем случае называемой Add Immediate. Т.е. не пятерка займет флеш, а инструкция у котой нужные биты будут равны пятерке. Так что не будем путать тёплое с мягким. Во флеше пятерки нет - есть инструкция, куда она входит. А если в вышеуказанном примере сделать const int с = 1 то вообще интересно может получится - вместо этого будет сгенерирована какая-нибудь инструкция Код inc acc которая инкрементирует аккумулятор. Тоже скажете, что константа во флеше?
--------------------
The truth is out there...
|
|
|
|
|
Jan 3 2018, 22:06
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата(razrab83 @ Jan 3 2018, 13:26)  Локальная const переменная на стадии сборки известна. Тогда подумайте и попробуйте собрать этот код: Код #include <inttypes.h> #include <stdlib.h> #include <stdio.h> #include <time.h>
void foo ( uint32_t in ) { const uint32_t test = in; const uint32_t *pTest = &test;
printf ( "%d, %p\n", test, pTest );
}
int main ( void ) { time_t t; srand((unsigned) time(&t));
foo ( 55 ); foo ( 77 );
foo ( rand() % 100 );
return 0; }
|
|
|
|
|
Jan 4 2018, 08:50
|
Участник

Группа: Участник
Сообщений: 52
Регистрация: 5-05-17
Пользователь №: 96 902

|
Цитата(sigmaN @ Jan 3 2018, 18:26)  Тоже скажете, что константа во флеше? Да. С точки зрения Си константа есть, а как там её компилятор реализовал - это уже дело компилятора. 2 QuasarКод const uint32_t test = in; убедили. такая константа инитится во время выполнения. Но "const uint32_t test = 5;" инитится известна при компиляции.
|
|
|
|
|
Jan 4 2018, 21:57
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата(razrab83 @ Jan 4 2018, 11:50)  2 QuasarКод const uint32_t test = in; убедили. такая константа инитится во время выполнения. Но "const uint32_t test = 5;" инитится известна при компиляции. Конкретно ваша "const uint32_t test = 5" соптимизируется непонятно во что. Но компилятор действует "в общем". А "в общем", модификатор const - гарант того, что конструкция "a = 5" вне блока инициализации невалидна. Остальное - следствие здравого смысла. Если можно const переменную убрать в rodata (FLASH или ro ОЗУ), её туда уберут, если нельзя - то нет, не уберут.
|
|
|
|
|
Jan 25 2018, 11:54
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
читаю pdf на IAR такой забавный пример с константами: Цитата String literals and other constants can be avoided by using initialized variables. For example, the following lines: CODE __ramfunc void test() { /* myc: initializer in ROM */ const int myc[] = { 10, 20 }; /* string literal in ROM */ msg("Hello"); }
Цитата can be rewritten to: CODE __ramfunc void test() { /* myc: initialized by cstartup */ static int myc[] = { 10, 20 }; /* hello: initialized by cstartup */ static char hello[] = "Hello"; msg(hello); }
|
|
|
|
|
Jan 25 2018, 15:26
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(sigmaN @ Jan 25 2018, 17:36)  Если __ramfunc, то как раз все данные должны быть только в оперативке... Например бутлоадер, который пишет во flash, не должен затрагивать данных из того-же flash. Поэтому проще было убрать в приведённом примере слово static и слово const вовсе - результат был бы такой же, а буков меньше.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jan 28 2018, 09:14
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата Привидите плиз пример когда 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++ я не использую это слово по старой привычке, и опираясь на логику некоторых местных товарищей, могу утверждать, что оно не нужно :-)
|
|
|
|
|
Jan 28 2018, 19:50
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Код 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 сработает? Сработает. Значит массив это указатель? А указатель это массив? На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот. Кто ответит? )
--------------------
The truth is out there...
|
|
|
|
|
Jan 28 2018, 20:03
|
Знающий
   
Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088

|
Цитата(sigmaN @ Jan 28 2018, 22:50)  Брэйкпоинт установленный на nop сработает? Сработает. Не сработает.
Сообщение отредактировал gerber - Jan 28 2018, 20:04
--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
|
|
|
|
|
Jan 28 2018, 20:40
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(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==  is 1 (i.e. true). И еще - по стандарту true совсем не обязан быть 1 Строка сравнивает числовое значение true , обычно 1, со значением из массива по первому индексу... глубокомысленно
|
|
|
|
|
Jan 28 2018, 21:31
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 18-03-12
Пользователь №: 70 865

|
Цитата(sigmaN @ Jan 28 2018, 22:50)  На много интереснее попросить привести примеры где именно массив поведет себя иначе чем указатель и наоборот. https://ideone.com/SLqzMw
|
|
|
|
|
Jan 28 2018, 21:34
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Ну имя массива это не 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)  Я думаю стоит сконцентрироваться на работе с массивом и индексами, сравнением массива с указателями.
Ответа на вполне конкретный вопрос пока не поступило. Так а кусок кода что Вы привели - какой смысл имеет и какое отношение к этому? Он попросту ошибочен
|
|
|
|
|
Jan 28 2018, 21:38
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 18-03-12
Пользователь №: 70 865

|
Мне и правда нужно было упоминать что строка девять и строка восемь это тот случай когда "массив поведет себя иначе чем указатель"?
|
|
|
|
|
Jan 29 2018, 07:45
|
Местный
  
Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031

|
Цитата в первом варианте в глобальной константе этот массив помещен в память 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])
|
|
|
|
|
Jan 29 2018, 15:46
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Код int (*ptr)[2]; Скомпилится? ptr это массив поинтеров? Поинтер на массив? Ваш варинт ответа
--------------------
The truth is out there...
|
|
|
|
|
Jan 29 2018, 15:55
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(sigmaN @ Jan 29 2018, 18:46)  Код int (*ptr)[2]; Скомпилится? ptr это массив поинтеров? Поинтер на массив? Ваш варинт ответа  это вот что https://www.youtube.com/watch?v=cdX8r3ZSzN4  А так то - указатель на массив, только вот по-моему редко кто такими конструкциями пользуется.
|
|
|
|
|
Jan 29 2018, 19:35
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(sigmaN @ Jan 29 2018, 18:46)  Код int (*ptr)[2]; Скомпилится? ptr это массив поинтеров? Поинтер на массив? Ваш варинт ответа  Указатель на массив. Теперь моя очередь =) Код char (*(*func(void))[3])(void); Цитата Скомпилится? Ваш варинт ответа 
|
|
|
|
|
Jan 29 2018, 21:14
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(sigmaN @ Jan 30 2018, 00:07)  А вот это я расшифровать пока не могу  Озвучу мысли, но я не уверен что это правильно func это массив указателей на функцию без параметров, которая возвращает указатель на фукнцию без параметров, которая возвращает char Ну, я Вас понимаю =) Подобные "сюрпризы" ни раз приходилось наблюдать в индусских говнопрограммах драйверах для процессоров различных платформ. Пример надуманный, и у вышеупомянутых коллек по ремеслу индусских товарищей было что-то чуть-чуть попроще, но лишь чуть-чуть P.S. func - это функция, не принимающая аргументов и возвращающая указатель на массив указателей на функции, которые возвращают char и не принимают параметров. Кстати, кто там хотел проверять кандидатов на знание языка Си - да элементарно предложите написать окружение для безошибочного компилирования следующей белиберды Код for(;P("\\n"),R-;P("|"))for(e=C;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2); Этой строке лет 20 уже - как гласит легенда - "первоапрельская шутка для UNIX-программистов" раньше была... Это покажет уровень понимания (!) языка в принципе. Я знаю, что знание языка отнюдь не всегда самое важное, однако эмбеддерам мое мнение нахрен никому не нужно считаю нужно уметь "думать" на языке, на котором пишешь.
Сообщение отредактировал Arlleex - Jan 29 2018, 21:21
|
|
|
|
|
Jan 29 2018, 21:20
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

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

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(DASM @ Jan 30 2018, 00:20)  Ну блин, я к Вам в кино в следущий раз подсяду и буду шептать "а убийца то - дворник. " Только я тоже пока не могу корректно компилящийся код под такую конструкцию написать, даже после такого ответа. Возникает идея - давать на собеседовании такие вот вопросы, и, если решил - не брать ни в коем случае, а то весь код в таком ключе и будет написан. Шарады и ребусы это конечно круто, но не в рабочем коде. А вообще это все ерунда я считаю. Пусть не знает вообще ни одного языка, но нарисует мне удобные интерфейсы - это супер. Я вот уже месяц торможу над проектом, при этом основной инструмент - планшет с пером, рисую взаимосвязи и интерфейсы, вот там реально мало чую у меня опыта. А эти шарады нафик не сдались Вам лично могу придумать полдесятка витиеватых примеров для решения Согласен, запутанные конструкции реально использовать трудно. Но менее сложные, такие как массивы указателей на функции, использовать приходилось, да и решение выглядело вполне изящно. Многие "фишки" C++ как раз раскрываются вот такими интересными конструкциями... Тот же механизм виртуальных функций...
|
|
|
|
|
Jan 29 2018, 21:34
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(Arlleex @ Jan 30 2018, 00:27)  Вам лично могу придумать полдесятка витиеватых примеров для решения Согласен, запутанные конструкции реально использовать трудно. Но менее сложные, такие как массивы указателей на функции, использовать приходилось, да и решение выглядело вполне изящно. Многие "фишки" C++ как раз раскрываются вот такими интересными конструкциями... Тот же механизм виртуальных функций... Вот после такой хрени таки да, auto как глоток воздуха становится. Ловлю себя на мысли, что то , чем не пользуешься - забывается мгновенно. Я синтаксис того что Вы написали однозначно не прочел бы ни с первого ни второго раза. В реальной работе крайне редко использую даже простой указатель на функцию. Если нужен - снова гуглю - где там скобочки и звездочки правильно расставить надо. Честно говоря такая моя "безграмотность" - не мешает. Проектирование программы, повторюсь, считаю куда более сложной задачей, чем собственно претворение готового проекта в код "использовать приходилось, да и решение выглядело вполне изящно" - да, согласен. Но я такие конструкции с гуглом пишу а не по памяти, обычно их пару раз в моих небольших проектах то и нужно всего использовать.
Эскизы прикрепленных изображений
|
|
|
|
|
Jan 29 2018, 21:57
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(DASM @ Jan 30 2018, 00:34)  Вот после такой хрени таки да, auto как глоток воздуха становится. Ловлю себя на мысли, что то , чем не пользуешься - забывается мгновенно. Я синтаксис того что Вы написали однозначно не прочел бы ни с первого ни второго раза... Честно говоря такая моя "безграмотность" - не мешает. Проектирование программы, повторюсь, считаю куда более сложной задачей, чем собственно претворение готового проекта в код... Насчет проектирования программы с Вами полностью согласен. Я просто люблю разные "трюки" в Си. Но стараюсь их избегать в реальном применении, потому как понимаю, что мой код, возможно, кому-то еще и поддерживать.
|
|
|
|
|
Jan 29 2018, 22:09
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
"кому-то еще и поддерживать." и 99 % это вы сами и будете, чертыхаясь и пытаясь понять свой же код. Я - за хорошие названия переменных и методов, вот тут тоже думать много надо над именем, (хотя собственно эти имена и отражают стадию проектирования). И если они хорошие - методы не нуждаются в комментариях (самодокометированный код_) за редким исключением. Еще думать как лучше вернуть несколько значений, раньше я передавал указатели, которые метод заполнял. Сейчас чаще завожу структуру отдельную и возращаю ее. Если структура выглядит как смесь совершенно несвязанных вещей - значит и метод у меня неправильный задуман, и его надо разбивать на несколько мелких более. В общем чем больше пишу, тем более простой код стараюсь делать, избегаю сложных конструкций в одну строку (зачем ? хвастать что можешь так ? перед самим собой что-ли?). Не стеснятся goto в меру . Лучше написать "туповатый" код но понятный даже новичку в С, чем вычурную констркцию if( (i == pi) == ptri ) и не заметить что первая ее часть возращает bool который ты ошибочно сравниваешь с int и это работает.. если int равен 1 и только.. как-то так.. а уж какие горы в ++ можно навернуть то это жуть. Страуструп признавался, что знает С++ где-то на 80..90 из 100. Куда уж смертным то
|
|
|
|
|
Jan 30 2018, 05:16
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата(DASM @ Jan 29 2018, 18:04)  +++! А какой у них при этом умный вид! Как правило это всякие КТН, с напускным видом умудренного опытом жирного кота. Если посмотреть потом их код - как правило это академическая муть с неочевидной перегрузкой операторов, неуклюжей попыткой засунуть ООП там, где оно вообще не надо итп. Реально полезного - ноль, собственно поэтому и ищут людей )) Стоит заметить, что ваши личные комплексы не являются темой данного обсуждения. Если у вас есть какие-то жизненные упущения, как то неполученный статус КТН, например, можете завести отдельную тему, где поплачитесь, а мы вас подбодрим добрым словом.
|
|
|
|
|
Jan 30 2018, 06:04
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

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

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

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

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Arlleex @ Jan 30 2018, 13:37)  Вы не правы. char (*(*func(void))[3])(void); да, не указатель (проглядел скобки справа), но это и не функция.  Строго говоря, func - есть имя функции, которое семантически является её адресом, т.е. технически это указатель. Всё выражение да, не указатель, но, строго, и не функция.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 30 2018, 09:11
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата(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; }
|
|
|
|
|
Jan 30 2018, 10:38
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(dxp @ Jan 30 2018, 12:08)  char (*(*func(void))[3])(void); да, не указатель (проглядел скобки справа), но это и не функция.  Строго говоря, func - есть имя функции, которое семантически является её адресом, т.е. технически это указатель. Всё выражение да, не указатель, но, строго, и не функция. Технически любое имя функции - это есть указатель. Даже Код void f1(void); Согласно Вашей логике, f1 - не функция? Стандартописатели из комитета ANSI C ошиблись с терминологией? Все выражение, все-таки - функция... Вернее, ее прототип. Код 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-ами (иначе Вас потом будут проклинать  ).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|