ptr, писал: "Во-первых, большинство архитектур поддерживают .."
Ну вот дальше можно и не писать ничего вовсе. Тут - форум за Ардуино, который на базе AVR, который .. ничего такого не поддерживает.
Arduino Due с ее ARM уже не Ардуино? А там адресация c ограниченным смещением очень активно используется. А смещение то всего, в зависимости от ситуации, от 255 до 4095 байт.
ptr .. и снова вы сваливаетесь на "программист === дурак": "А программист не способен постоянно безошибочно контролировать, какая функция TS (Trhread Safe), а какая нет." Напомню постулат из психологии: "Каждый всегда судит о других по себе любимому"...
Напомню народную мудрость: "Не ошибается только тот, кто ничего не делает"
Я ошибаюсь часто, каждый день по многу раз. То SQL на мой запрос отругается, то компилятор на мой код, то кто-то из моей команды укажет мне на мою ошибку. Каждый день! Я дурак по-вашему?
А проблема с Not Thread Safe функциями опасна тем, что она может не проявиться ни на этапе отладки, ни на этапе тестирования, а вылазить только у нескольких клиентов, да и то, в момент пиковых загрузок раз в месяц. Попробуй поймай потом такую багу.
Тут программирование микроконтроллеров! Ну не бывает тут "больших приложений"! :)
Не согласен. Несколько лет активно занимался программированием Z80. Часто, всего с 16Кб памяти. Иногда, с 48Кб. На все, и на программу и на данные. В основном, на ассемблере.
Например, делали прошивку Z80 для принтера. Вчетвером. Я занимался управлением непосредственно двигателями и иголками печатающей головки и обменом по Centronix, предоставляя функции для более высокого уровня. Девочка у нас рисовала шрифты и оформляла документацию. Другой парень занимался интерпретацией ESC команд принтера на C. Третий - железом. Исходников было свыше сотни тысяч строк, если считать загружаемые шрифты и калибровочные данные для разных игольчатых головок. У них не было обратной связи, а время на выход и убирание иголки плавало даже у разных партий, не то что у разных производителей.
Это, конечно, несравнимо меньше текущих моих проектов с десятками и сотнями миллионов строк, но требовало уже вполне взрослого проектного подхода, как для больших приложений.
1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!
2. Мы все ошибаемся, и я тоже не исключение. Точно также "по нескольку раз в час". :) Но, я не делаю из этого никакой проблемы, ибо это нормально. И отказываться от эффективных способов программирования и уж тем более СОВЕТОВАТЬ другим что "так не надо" - не могу себе позволить. Слишком велико отличие подходов к программированию микроконтроллеров от "общих" методик. И цена говнокода - слишком высока на мой взгляд: вынужденный, по неумению переход на следующие линейки по мощности/производительности там, где это вовсе ни разу не востребовано.
Да собственно, сами посмотрите коды от того же Dimax-а для тинек! Одни сплошные регистровые глобалы.. :)
Да и ещё: относительно большими я привык называть проекты от 5-10 миллионов строк кода. Так, ежели вчё. :)
Ну и "взрослый подход" рекомендован даже для относительно маленьких проектов .. хотя бы в части "самодокументирования" .. порой, без документирования, даже через пару месяцев смотришь на код и не можешь понять "а нафига так наворочено" .. тут как говорится "размер не имеет значения". :)
Евгений написал, что люди УЖЕ имеющие квалификацию не являются целевой аудиторией.
Учиться же следует просто правильному програмированию, не програмированию микроконтроллеров, или програмированию суперкластеров, а ПРОСТО грамотному програмированию.
В корне не согласен с тем, что новичку нужно учиться, как Вы пишите: "порграмированию с учетом особенностей архитектуры и .т.д.".
Учиться нужно тому, как писать качественный код. То есть без глобалов, с избеганием повторяемости, использованием наследования и пр.
А ПОТОМ, когда человек начнет писать сам, он уже САМ разберется, где можно экономить память и скорость.
Когда-то давно я решил овладеть новым для себя навыком сварки оптоволокна. Меня и жену (которая потом много лет этим занималась) учил старый дедушка из бывшего ВНИИКП. Так вот его любимая фраза была такая: "Ты делай хорошо, плохо - оно само получится.". В итоге потом, когда было нужно, супруга варила в стойке, когда помошник держал сварку на вытянутой руке и при свете налобного фонарика. НО ПОТОМ. А сначала нужно было научиться ПРАВИЛЬНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ОПЕРАЦИЙ.
А есть вариант статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Нечто средние между static и обычной переменной внутри функции.
статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.
1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!
И что с того? Если редкость, то значит уже "такого не бывает"? И код на Due нельзя переносить с AVR? По мне так вполне нормальный подход. Когда не влазишь в 328, переходишь на 2560. Не устраивает 2560, переходишь на ARM. И необходимость переписывать при этом переходе полкода - признак недальновидности.
И только не надо мне говорить про "оптимизацию", чтобы влезть в 328 или 2560. Это оправдано только на тиражах в сотни экземляров. Для примера, себестоимость часа работы программиста ~2000 рублей. Даже если не платить вообще налоги и выдавать зарплату всю в конверте, будет ~1000 рублей. На руки тогда хотя бы 80 тыс. в месяц получиться, если урезать до безобразия накладые расходы, капитальные вложения, management fee и норму прибыли. При стоимости Due порядка 800 рублей, лишняя неделя работы программиста окупится только при тираже свыше 60 единиц.
И вообще, смешно говорить о стоимости МК, когда в стоимости проекта, при любых раскладах, она составляет единицы процентов. Выбирается тот, на котором быстрее можно реализовать проект.
Кстит, ESP8266, стоимостью, как Arduino Nano вполне себе 32-х разрядный 80МГц (до 160МГц) процессор. Так что при нехватке памяти или быстродейстия переход на него вообще не приведет к дополнительным затратам на комплектующие.
Цитата:
2. Мы все ошибаемся, и я тоже не исключение.
А значит, Вы способны по ошибке вызвать Not Thread Safe функцию (свою или библиотечную) в многопоточном проекте, что приведет потом к долгим часам поиска этой баги. Что и требовалось доказать.
А есть вариант статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Нечто средние между static и обычной переменной внутри функции.
Если имелось в виду, что для каждой нити будут свои статические переменные, то в C это не возможно, да и бессмысленно. Сама идеология нитей подразумевает, что у них общее, а не раздельное адресное пространство. А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.
Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.
Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива.
То есть пока функция всего одна всё будет корректно.
Если будет вызываться эта же функция но нацеленная на другой датчик, она так же в этот массив положит свои значения. И в итоге в нём будет путаница из значений.
А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.
Парралельно да. Ну что бы не городить огород было бы удобно. static не для всех вызовов функций, а для каждого вызова свой.
Мне дико неловко, но Вы про объектное програмирование слышали?
То, что Вы хотите - называется объект. Для каждого вызова - новый, Вы не поверите! И все переменные у него свои и никуда не деваются между обращениями к методам...
Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива.
То есть пока функция всего одна всё будет корректно.
Если будет вызываться эта же функция но нацеленная на другой датчик, она так же в этот массив положит свои значения. И в итоге в нём будет путаница из значений.
#define ERR_SUCCESS 0
#define ERR_NULL_POINTER 16
#define ERR_NO_MEMORY 32
#define SENSOR_DATA_ARRAY_SIZE 8
typedef struct sensor_data_st {
int sensor_no;
int *data_array;
} sensor_data_t;
int get_sensor_data(sensor_data_t *sensor_data)
{
int i;
if (!sensor_data) return ERR_NULL_POINTER;
if (!sensor_data->data_array)
{
sensor_data->data_array=malloc(SENSOR_DATA_ARRAY_SIZE*sizeof(int));
if (!sensor_data->data_array) return ERR_NO_MEMORY;
}
....
sensor_data->data_array[i]=get_sensor_status(sensor_data->sensor_no);
...
}
Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.
Мне дико неловко, но Вы про объектное програмирование слышали?
Ваше дело, но в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
Да и по сути, Вы вдруг Архата напомнили. Он хороший програмист, как бы не ругался с Евгением, но у него пунктик на тему ООП. Он его органически не переносит. Что не может не вызывать добрые усмешки.
Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.
Спаибо конечно, но именно от этого я и хотел избавиться.
Вы просто выделили область памяти и наладили адресную эмуляцию. Я делаю немного по другому, но смысл тот же. (Общая структура для всех возможных данных)
в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
Всё нужно делать с умом, там где это нужно и там, где (и "так, как") это эффективно. Тогда и с памятью всё нормально и с быстродействием. А ежели без ума, ...
Я вот сейчас новый "этюд" пишу, там есть отголосок как раз таких холиваров на тему "вот это использовать нельзя, а вот это нужно" - моя неоднократно озвученная здесь позиция, что применять можно и нужно всё - только к месту и с умом: "Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан. Понятное дело, красить стены молотком неудобно и качества не получишь, но это ещё не повод забивать гвозди малярной кистью".
findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.
Я вот сейчас новый "этюд" пишу, там есть отголосок как раз таких холиваров на тему "вот это использовать нельзя, а вот это нужно" - моя неоднократно озвученная здесь позиция, что применять можно и нужно всё - только к месту и с умом: "Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан. Понятное дело, красить стены молотком неудобно и качества не получишь, но это ещё не повод забивать гвозди малярной кистью".
+1! И даже глобалы хороши, если проект на один-два экрана помешается.
findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.
У меня структура со всеми возможными состояниями и значениями всего и вся. Но просто подумал что есть возможность легко вынести наружу.
в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
"вот это использовать нельзя, а вот это нужно"
"Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан.".
Во-первых, я сказал "не рекомендую", а не "нельзя". Можно, конечно, но надо понимать при этом, что за все надо платить. И цена за удобство ООП - потеря в производительности, увеличение размера кода и сложности в отладке, при наличии множественных наследований с перегрузками.
Во-вторых, я очень люблю ООП при построении пользовательских интерфейсов и ненавижу его в пакетных заданиях. Потому что создать большую и сложную иерархию классов так, чтобы потом не было мучительно больно на нее смотреть через год модификаций - очень сложно. А ловить баги в таком коде жутко долго.
То есть, обожая QT, я для ядра Linux С++ даже не подумаю предложить )
+1! И даже глобалы хороши, если проект на один-два экрана помешается.
Глобальные переменные ничем не заменить для обработчиков прерываний. Так что они, безусловно, необходимы. Просто их количество не должно расти неконтролируемо по мере развития проекта.
.. Евгений написал, что люди УЖЕ имеющие квалификацию не являются целевой аудиторией. Учиться же следует просто правильному програмированию, не програмированию микроконтроллеров, или програмированию суперкластеров, а ПРОСТО грамотному програмированию. ...
Ну .. тут много удивительных людей .. видимо место такое. Я уже неоднократно писал и могу написать ещё 100500 раз, что учить надо не абстрактному "правильному программированию" сферических коней в вакууме, а оптимальному программированию, тому кторое дает выигрыш И по размеру кода И по скорости его исполнения. Как раз новички - и есть та самая целевая аудитория, за правильное обучение которой я и ломаю копья тут. Чего Евгений - в корне отказывается признавать.
.. а Вы (удивительные люди) предлагаете учить их "абстрактному управлению авто" .. а то что Автобус, КАМАЗ с прицепом и велосипед с самокатом в корне отличаются по способам и методам управления .. это они "потом познают". То бишь тормозить пяткой на самокате - самое то, но вот мало кому придет в голову делать это на КАМАЗе .. а вы предлагаете ИМЕННО ТАКОЙ ПОДХОД.
Чего тогда удивляться задаваемым тут вопросам типа "где гидравлический усилитель руля на этом самокате?" :)
что учить надо не абстрактному "правильному программированию" сферических коней в вакууме, а оптимальному программированию, тому кторое дает выигрыш И по размеру кода И по скорости его исполнения.
Сколько людей, столько мнений, но если у меня будет стоят выбор, кого принять на работу: программиста пишущего оптимальные по коду и скорости исполнения программы или программиста, пишущего "правильно", а значит допускающего минимум ошибок в коде, то я выберу второго.
Потому что обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся.
Ваш выбор есть тавтология. Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):
1. Десктопное программирование "офисных" приложений. Как правило достаточно объемные проекты (скажем 1С-зарплата) .. есть свои критерии правильности, в частности модульность кода опирающаяся на развесистый ООП. Да, тут повальное использование глобалов (руление наклоном корпуса) есть зло.
2. Десктопное программирование "игровых" приложений. Как правило это в основном графика и звук .. и тут уже несколько иные критерии "правильности". Попробуйте реализовать какой-нибудь Дуум на базе иерархии классов ..
Это как-бы "общее программирование" .. и то оно РАЗНОЕ.
3. Программирование баз данных.SQL, оно же реляционная алгебра. Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта". Я бы хотел посмотреть на реализацию сортировки выборки по приличной табличке и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)
5. Программирование микроконтроллеров .. этот форум. То, что должно начинаться словами: "забудьте всё чему вас учили сферические преподаватели вакуума". Ибо "тормозить пяткой" - наше фсё.
.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..
Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".
.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..
Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".
Я же объяснил почему я так считаю: "обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся". И у меня уже был не раз печальный опыт, когда, вроде бы хорошего программиста, приходилось увольнять. Так как с его кодом через год он уже и сам не мог работать, не то что остальные.
А программировать на проектах приходится что угодно. Например, для РосСетей (ТулаЭнерго) от сложных хранимых процедур SQL и навороченных сервисах на C# на мощных серверах до контроллеров Smart Grid, собирающих события и показания с приборов учета по PLC и отсылающих их по GPRS. А уж что только не программировали для Почты России, тут вообще не перечислить.
Если бы анекдот... Тут как на дороге. Не важно, на Камазе или на велосипеде - ПДД для всех одни.
Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):
Я же явно сказал! "Правильно" - это соблюдая ряд правил, которые позволяют минимизировать количество ошибок при написании программы. И эти правила могут быть разными, для разных языков, но для С они одинаковы хоть на мэйнфрейме, хоть на МК.
Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта".
Простите, улыбнуло. Любой SELECT/INSERT/UPDATE уже есть цикл по сути. Я уж не говорю об операциях с курсорами и явными организациями циклов в том же T-SQL или PL/SQL. Я программирую и на C и на SQL. Без всякого выворачивания мозга )
Цитата:
Я бы хотел посмотреть на реализацию сортировки выборки по приличной табличке
А ORDER BY для чего? Или вы про то, как это SQL сервер делает? Я думаю, обычным quick sort с последующим слиянием отсортированных фрагментов.
Цитата:
и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)
У меня есть отчеты, которым при запуске, бывало, несколько десятков тысяч параметров доставалось. Если передавать параметры через БД, то можно и сотни тысяч переварить.
Я про то, что типовой вопрос С-шника, программирующего СУБД на SQL это "а как тут цикл организовать?" .. нету циклов в реляционной алгебре от слова "совсем" .. и разные "курсоры" и прочие "навороты" в конкретных релизах - есть КОСТЫЛИ тем, кто не может решать задачи реляционной алгебры .. то бишь "вывернуть мозг" от алгоритмическго языка к реляциям. Равно как и явных (циклических) сортировок нет. Есть один единственный ORDER BY и что там лежит под ним, и каким набором циклов реализован SELECT .. реляционщику "по-барабану". И то, что "правильно" у реляционщика .. ровно наоборот у С-шника.
А ваш выбор "способный писать правильно", в смысле "без ошибок" .. как раз и есть ОПТИМАЛЬНОЕ программирование с использованием красивых решений и уже "типовых" алгоритмов. То есть - тавтология.
И, перечитайте себя: "я не рекомендую использовать глобальные переменные" .. это по-вашему правильно тут, в программировании микроконтроллеров? Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах! И после этого вы побежите покупать "побольше и помощнее" .. так и НЕ научившись программировать микроконтроллеры.
Это я и называю "а потом мы вам водичку нальем", а Вы пока потренируйтесь прыгать в пустой бассейн. :)
Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах!
А пруф где? Или хотя бы аргументы?
Объясняю. Для того, чтобы обратиться к глобальной переменной есть два варианта:
1. Загрузить ее адрес в регистр X, Y или Z, а только потом обратиться к переменной.
2. Загрузить в регистра X, Y или Z начало сегмента статических переменных и адресоваться через смещение от регистра ко всем глобальным переменным не перезагружая адрес. Но это пройдет только в том случае, если общий объем глобальных переменных меньше 64 байт.
То же самое относится и к параметрам функции, но только там речь идет об указателе стека. И если объем глобальных переменных легко представить более, чем 64 байта, то для параметров одной функции это уже редкость.
Итого, сэкономив 2 байта в стеке на адрес переменной, увеличиваем расход памяти программ, да еще и понижаем быстродействие. И это при том, что расширить оперативную память для AVR возможностей полно, а программную - нет.
Вот, вот .. начинается. :) Вы случаем AVR с пиками не попутали? Тут, по секрету, есть прямая адресация глобала из команды. Все 64кб адресов и 2 слова программы (1 команда, 2 такта). Может, все-таки изучить матчасть, вместо предложения обучения "сферическим коням в вакууме"? .. это собственно и есть то, про что пишу: детскому самокату не требуется гидравлика. Она ему ПРОТИВОПОКАЗАНА. :)
Ок. Давайте по порядку. Ваш совет "глобалы == зло" подразумевает для AVR и микроконтроллеров "в целом" (есть конечно нюансы, но несущественно):
1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.
Ситуацию с "уже в регистре" не рассматриваем, поскольку локалов типа long можно считать "как таковых нет", это с одной стороны. А с другой стороны, если весь код повально делается с истреблением глобалов, то практически ВСЁ размещено в памяти. Ибо на все функции регистров не хватит - гарантировано. б) подпрограмный переход, с сохранением точки возврата, который есть в любом случае модульного программирования (функции).
Среднее количество параметров в функциях = 3.5, средний используемый тип 2.5 байта. Для новичков, в целях перестраховки берем 4 байта, хотя бы потому, что любимый millis() возвращает long. Итого, только на вызов функции тратится 3.5 * 4 = 14 байт стека и 3.5*16/32 <24>(в среднем) = <84> байта флеша для кода подготовки вызова. Кроме этого, функция имеет локалы .. их среднее количество также 3.5, и для типа long (напомню - это любимый тип всех начинающих) на регистрах будет только 1 переменная .. итого 2.5 * 4 = 10 байт плюсом из стека "долой". Ещё кроме этого, средняя функция сохраняет 3-4 (long!) регистра из пула "локальных" от предыдущего вызова .. пусть будет ещё пара байт.
Итого, средняя функция "программирования без глобалов" тянет на вызов 14 + 10 + 2 = 26 байт стека ПОМИМО хранения точки возврата. Плюс дополнительное время исполнения для примерно 50 команд из которых около трети в 2 такта.
Соответственно, "стека не хватит" определяется просто: делим имеющееся пространство стека на примерно 20-30 и смотрим допустимую глубину вложения вызовов рекомендуемого вами и автором опуса "ООП подхода". И это для средних, относительно простых функций. В случае "тяжелого кода" от новичка (типа классов Serial, Print и др.) этот показатель можно ускорить как миниум вдвое.
Неужели такую банальщину надо расписывать специалистам, берущимся ОБУЧАТЬ новичков?!?
Аналогично разбираются и ваши возражения предыдущего поста. Лично меня Вы уже смогли удивить и сильно .. :)
Да, кстати. Я ещё опустил рассмотрение вопроса ВОЗВРАТА результата функций обратно в вычисление и .. память. Так что, для "безглобального программирования микроконтроллеров" всё становится настолько печальным, что в пору бежать за "следующим поколением".. от неумения и догматического применения "рассово-правильного" подхода. :)
На самом деле "правилен" только один подход: оптимальное программирование. И оно .. РАЗНОЕ для каждого отдельного случая: SQL, десктоп, игры, сервера, транспьютеры и .. микроконтроллеры.
И до тех пор пока люди, берущие на себя ПРАВО ОБУЧАТЬ ДРУГИХ не начнут учить ХОРОШЕМУ .. надо чтобы хоть кто-то их останавливал в их стараниях учить плохому.
1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.
Не понял, мы перешли к обсуждению 32-х битных МК? При чем тут long? Если включить мозги, то вместо кучи глобальных и статических переменных, кроме одной глобальной, необходимой обработчикам прерываний, у нас будет одна переменная, указатель на которую мы и будем передавать вызываемым функциям. Handle это принято называть.
В связи с идеей, передавать функциям не хендл, а все по одному, да еще не указателями, а по значениям, все нижеследующее я удалю, чтобы не позорить оппонента.
Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)
Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)
Похоже пора завязывать, а то оппонент сейчас еще скажет, что одной глобальной переменной для всех обработчиков прерываний не хватит )
Причем с его страстью к оптимизации совершенно не ясно, почему он решил передавать параметры через стек, а не через регистры, что GCC вполне позволяет.
ptr, я заметил что не поняли. Ну да ладно .. со временем придет и понимание.
Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта. И напрямую применяют огульные рекомендации от "сферическими гуру", что называется "на веру". А равно "типовые библиотеки", писанные как правило программистами "общего профиля" .. то бишь для "сферических коней в вакуумах", один набор иерархии Serial чего стоит ... Вы полистайте форум таки.. :)
Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта.
Программировать на C без использования указателей невозможно. Даже
Serial.println ("Hello World!");
уже использование char *
И в третий раз повторю, в том числе и про новичков:
"Обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся"
где под "качественным" подразумевается "соблюдая ряд правил, которые позволяют минимизировать количество ошибок при написании программы".
ptr, писал: "Во-первых, большинство архитектур поддерживают .."
Ну вот дальше можно и не писать ничего вовсе. Тут - форум за Ардуино, который на базе AVR, который .. ничего такого не поддерживает.
Arduino Due с ее ARM уже не Ардуино? А там адресация c ограниченным смещением очень активно используется. А смещение то всего, в зависимости от ситуации, от 255 до 4095 байт.
ptr .. и снова вы сваливаетесь на "программист === дурак": "А программист не способен постоянно безошибочно контролировать, какая функция TS (Trhread Safe), а какая нет." Напомню постулат из психологии: "Каждый всегда судит о других по себе любимому"...
Напомню народную мудрость: "Не ошибается только тот, кто ничего не делает"
Я ошибаюсь часто, каждый день по многу раз. То SQL на мой запрос отругается, то компилятор на мой код, то кто-то из моей команды укажет мне на мою ошибку. Каждый день! Я дурак по-вашему?
А проблема с Not Thread Safe функциями опасна тем, что она может не проявиться ни на этапе отладки, ни на этапе тестирования, а вылазить только у нескольких клиентов, да и то, в момент пиковых загрузок раз в месяц. Попробуй поймай потом такую багу.
Тут программирование микроконтроллеров! Ну не бывает тут "больших приложений"! :)
Не согласен. Несколько лет активно занимался программированием Z80. Часто, всего с 16Кб памяти. Иногда, с 48Кб. На все, и на программу и на данные. В основном, на ассемблере.
Например, делали прошивку Z80 для принтера. Вчетвером. Я занимался управлением непосредственно двигателями и иголками печатающей головки и обменом по Centronix, предоставляя функции для более высокого уровня. Девочка у нас рисовала шрифты и оформляла документацию. Другой парень занимался интерпретацией ESC команд принтера на C. Третий - железом. Исходников было свыше сотни тысяч строк, если считать загружаемые шрифты и калибровочные данные для разных игольчатых головок. У них не было обратной связи, а время на выход и убирание иголки плавало даже у разных партий, не то что у разных производителей.
Это, конечно, несравнимо меньше текущих моих проектов с десятками и сотнями миллионов строк, но требовало уже вполне взрослого проектного подхода, как для больших приложений.
Ptr, 2 момента:
1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!
2. Мы все ошибаемся, и я тоже не исключение. Точно также "по нескольку раз в час". :) Но, я не делаю из этого никакой проблемы, ибо это нормально. И отказываться от эффективных способов программирования и уж тем более СОВЕТОВАТЬ другим что "так не надо" - не могу себе позволить. Слишком велико отличие подходов к программированию микроконтроллеров от "общих" методик. И цена говнокода - слишком высока на мой взгляд: вынужденный, по неумению переход на следующие линейки по мощности/производительности там, где это вовсе ни разу не востребовано.
Да собственно, сами посмотрите коды от того же Dimax-а для тинек! Одни сплошные регистровые глобалы.. :)
Да и ещё: относительно большими я привык называть проекты от 5-10 миллионов строк кода. Так, ежели вчё. :)
Ну и "взрослый подход" рекомендован даже для относительно маленьких проектов .. хотя бы в части "самодокументирования" .. порой, без документирования, даже через пару месяцев смотришь на код и не можешь понять "а нафига так наворочено" .. тут как говорится "размер не имеет значения". :)
Архат! Вы удивительный человек.
Евгений написал, что люди УЖЕ имеющие квалификацию не являются целевой аудиторией.
Учиться же следует просто правильному програмированию, не програмированию микроконтроллеров, или програмированию суперкластеров, а ПРОСТО грамотному програмированию.
В корне не согласен с тем, что новичку нужно учиться, как Вы пишите: "порграмированию с учетом особенностей архитектуры и .т.д.".
Учиться нужно тому, как писать качественный код. То есть без глобалов, с избеганием повторяемости, использованием наследования и пр.
А ПОТОМ, когда человек начнет писать сам, он уже САМ разберется, где можно экономить память и скорость.
---------------------------------------------------------
Когда-то давно я решил овладеть новым для себя навыком сварки оптоволокна. Меня и жену (которая потом много лет этим занималась) учил старый дедушка из бывшего ВНИИКП. Так вот его любимая фраза была такая: "Ты делай хорошо, плохо - оно само получится.". В итоге потом, когда было нужно, супруга варила в стойке, когда помошник держал сварку на вытянутой руке и при свете налобного фонарика. НО ПОТОМ. А сначала нужно было научиться ПРАВИЛЬНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ОПЕРАЦИЙ.
А есть вариант статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Нечто средние между static и обычной переменной внутри функции.
статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.
1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!
И что с того? Если редкость, то значит уже "такого не бывает"? И код на Due нельзя переносить с AVR? По мне так вполне нормальный подход. Когда не влазишь в 328, переходишь на 2560. Не устраивает 2560, переходишь на ARM. И необходимость переписывать при этом переходе полкода - признак недальновидности.
И только не надо мне говорить про "оптимизацию", чтобы влезть в 328 или 2560. Это оправдано только на тиражах в сотни экземляров. Для примера, себестоимость часа работы программиста ~2000 рублей. Даже если не платить вообще налоги и выдавать зарплату всю в конверте, будет ~1000 рублей. На руки тогда хотя бы 80 тыс. в месяц получиться, если урезать до безобразия накладые расходы, капитальные вложения, management fee и норму прибыли. При стоимости Due порядка 800 рублей, лишняя неделя работы программиста окупится только при тираже свыше 60 единиц.
И вообще, смешно говорить о стоимости МК, когда в стоимости проекта, при любых раскладах, она составляет единицы процентов. Выбирается тот, на котором быстрее можно реализовать проект.
Кстит, ESP8266, стоимостью, как Arduino Nano вполне себе 32-х разрядный 80МГц (до 160МГц) процессор. Так что при нехватке памяти или быстродейстия переход на него вообще не приведет к дополнительным затратам на комплектующие.
2. Мы все ошибаемся, и я тоже не исключение.
А значит, Вы способны по ошибке вызвать Not Thread Safe функцию (свою или библиотечную) в многопоточном проекте, что приведет потом к долгим часам поиска этой баги. Что и требовалось доказать.
А есть вариант статической переменной для каждого вызова функции. То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для этого вызова.
Нечто средние между static и обычной переменной внутри функции.
Если имелось в виду, что для каждой нити будут свои статические переменные, то в C это не возможно, да и бессмысленно. Сама идеология нитей подразумевает, что у них общее, а не раздельное адресное пространство. А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.
Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.
Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива.
То есть пока функция всего одна всё будет корректно.
Если будет вызываться эта же функция но нацеленная на другой датчик, она так же в этот массив положит свои значения. И в итоге в нём будет путаница из значений.
И что Вы предлагаете? Какой механизм использовать?
А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.
Парралельно да. Ну что бы не городить огород было бы удобно. static не для всех вызовов функций, а для каждого вызова свой.
Это оправдано только на тиражах в сотни экземляров.
Поправлю, даже тысяча не особо отбивает.
А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.
Парралельно да. Ну что бы не городить огород было бы удобно. static не для всех вызовов функций, а для каждого вызова свой.
Мне дико неловко, но Вы про объектное програмирование слышали?
То, что Вы хотите - называется объект. Для каждого вызова - новый, Вы не поверите! И все переменные у него свои и никуда не деваются между обращениями к методам...
Еще раз - простите, просто не мог не поглумиться.
Мне дико неловко, но Вы про объектное програмирование слышали?
Навыка ООП у меня нет, да и нужен ли он для таких простых вещей.
Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива.
То есть пока функция всего одна всё будет корректно.
Если будет вызываться эта же функция но нацеленная на другой датчик, она так же в этот массив положит свои значения. И в итоге в нём будет путаница из значений.
Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.
Мне дико неловко, но Вы про объектное програмирование слышали?
Ваше дело, но в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
Напортачил в коде. Исправил по месту.
PTR! Это же не Вам написано было, а новичку.
Да и по сути, Вы вдруг Архата напомнили. Он хороший програмист, как бы не ругался с Евгением, но у него пунктик на тему ООП. Он его органически не переносит. Что не может не вызывать добрые усмешки.
Всякому овощу - свой фрукт, как говорят. ;)
Мне дико неловко, но Вы про объектное програмирование слышали?
Навыка ООП у меня нет, да и нужен ли он для таких простых вещей.
если Вы не ограничены пока памятью для размещения кода - то да, конечно переводить.
Вы - новичек и отлаживать ООП - гораздо проще из-за читаемости.
К тому же объект можно отладить отдельно и быть в нем уверенным, а потом включать в Вашу котельную.
Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.
Спаибо конечно, но именно от этого я и хотел избавиться.
Вы просто выделили область памяти и наладили адресную эмуляцию. Я делаю немного по другому, но смысл тот же. (Общая структура для всех возможных данных)
Просто подумал, может есть более простое решение.
в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
Всё нужно делать с умом, там где это нужно и там, где (и "так, как") это эффективно. Тогда и с памятью всё нормально и с быстродействием. А ежели без ума, ...
Я вот сейчас новый "этюд" пишу, там есть отголосок как раз таких холиваров на тему "вот это использовать нельзя, а вот это нужно" - моя неоднократно озвученная здесь позиция, что применять можно и нужно всё - только к месту и с умом: "Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан. Понятное дело, красить стены молотком неудобно и качества не получишь, но это ещё не повод забивать гвозди малярной кистью".
findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.
Я вот сейчас новый "этюд" пишу, там есть отголосок как раз таких холиваров на тему "вот это использовать нельзя, а вот это нужно" - моя неоднократно озвученная здесь позиция, что применять можно и нужно всё - только к месту и с умом: "Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан. Понятное дело, красить стены молотком неудобно и качества не получишь, но это ещё не повод забивать гвозди малярной кистью".
+1! И даже глобалы хороши, если проект на один-два экрана помешается.
Вы - новичек и отлаживать ООП - гораздо проще из-за читаемости.
К тому же объект можно отладить отдельно и быть в нем уверенным, а потом включать в Вашу котельную.
У меня нет навыка в ООП, где можно кратко ознакомиться с принципами и механизмами реализации.
findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.
У меня структура со всеми возможными состояниями и значениями всего и вся. Но просто подумал что есть возможность легко вынести наружу.
Ну, массивы структур тоже никто не отменял :)
Ну, массивы структур тоже никто не отменял :)
Типа того. Только в структуре сразу создан двухмерный массив под все возможные датчики.
в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.
"вот это использовать нельзя, а вот это нужно"
"Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан.".
Во-первых, я сказал "не рекомендую", а не "нельзя". Можно, конечно, но надо понимать при этом, что за все надо платить. И цена за удобство ООП - потеря в производительности, увеличение размера кода и сложности в отладке, при наличии множественных наследований с перегрузками.
Во-вторых, я очень люблю ООП при построении пользовательских интерфейсов и ненавижу его в пакетных заданиях. Потому что создать большую и сложную иерархию классов так, чтобы потом не было мучительно больно на нее смотреть через год модификаций - очень сложно. А ловить баги в таком коде жутко долго.
То есть, обожая QT, я для ядра Linux С++ даже не подумаю предложить )
+1! И даже глобалы хороши, если проект на один-два экрана помешается.
Глобальные переменные ничем не заменить для обработчиков прерываний. Так что они, безусловно, необходимы. Просто их количество не должно расти неконтролируемо по мере развития проекта.
Ну .. тут много удивительных людей .. видимо место такое. Я уже неоднократно писал и могу написать ещё 100500 раз, что учить надо не абстрактному "правильному программированию" сферических коней в вакууме, а оптимальному программированию, тому кторое дает выигрыш И по размеру кода И по скорости его исполнения. Как раз новички - и есть та самая целевая аудитория, за правильное обучение которой я и ломаю копья тут. Чего Евгений - в корне отказывается признавать.
.. а Вы (удивительные люди) предлагаете учить их "абстрактному управлению авто" .. а то что Автобус, КАМАЗ с прицепом и велосипед с самокатом в корне отличаются по способам и методам управления .. это они "потом познают". То бишь тормозить пяткой на самокате - самое то, но вот мало кому придет в голову делать это на КАМАЗе .. а вы предлагаете ИМЕННО ТАКОЙ ПОДХОД.
Чего тогда удивляться задаваемым тут вопросам типа "где гидравлический усилитель руля на этом самокате?" :)
что учить надо не абстрактному "правильному программированию" сферических коней в вакууме, а оптимальному программированию, тому кторое дает выигрыш И по размеру кода И по скорости его исполнения.
Сколько людей, столько мнений, но если у меня будет стоят выбор, кого принять на работу: программиста пишущего оптимальные по коду и скорости исполнения программы или программиста, пишущего "правильно", а значит допускающего минимум ошибок в коде, то я выберу второго.
Потому что обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся.
Ваш выбор есть тавтология. Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):
1. Десктопное программирование "офисных" приложений. Как правило достаточно объемные проекты (скажем 1С-зарплата) .. есть свои критерии правильности, в частности модульность кода опирающаяся на развесистый ООП. Да, тут повальное использование глобалов (руление наклоном корпуса) есть зло.
2. Десктопное программирование "игровых" приложений. Как правило это в основном графика и звук .. и тут уже несколько иные критерии "правильности". Попробуйте реализовать какой-нибудь Дуум на базе иерархии классов ..
Это как-бы "общее программирование" .. и то оно РАЗНОЕ.
3. Программирование баз данных.SQL, оно же реляционная алгебра. Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта". Я бы хотел посмотреть на реализацию сортировки выборки по приличной табличке и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)
5. Программирование микроконтроллеров .. этот форум. То, что должно начинаться словами: "забудьте всё чему вас учили сферические преподаватели вакуума". Ибо "тормозить пяткой" - наше фсё.
.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..
Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".
.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..
Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".
Я же объяснил почему я так считаю: "обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся". И у меня уже был не раз печальный опыт, когда, вроде бы хорошего программиста, приходилось увольнять. Так как с его кодом через год он уже и сам не мог работать, не то что остальные.
А программировать на проектах приходится что угодно. Например, для РосСетей (ТулаЭнерго) от сложных хранимых процедур SQL и навороченных сервисах на C# на мощных серверах до контроллеров Smart Grid, собирающих события и показания с приборов учета по PLC и отсылающих их по GPRS. А уж что только не программировали для Почты России, тут вообще не перечислить.
Если бы анекдот... Тут как на дороге. Не важно, на Камазе или на велосипеде - ПДД для всех одни.
Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):
Я же явно сказал! "Правильно" - это соблюдая ряд правил, которые позволяют минимизировать количество ошибок при написании программы. И эти правила могут быть разными, для разных языков, но для С они одинаковы хоть на мэйнфрейме, хоть на МК.
Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта".
Простите, улыбнуло. Любой SELECT/INSERT/UPDATE уже есть цикл по сути. Я уж не говорю об операциях с курсорами и явными организациями циклов в том же T-SQL или PL/SQL. Я программирую и на C и на SQL. Без всякого выворачивания мозга )
Я бы хотел посмотреть на реализацию сортировки выборки по приличной табличке
А ORDER BY для чего? Или вы про то, как это SQL сервер делает? Я думаю, обычным quick sort с последующим слиянием отсортированных фрагментов.
и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)
У меня есть отчеты, которым при запуске, бывало, несколько десятков тысяч параметров доставалось. Если передавать параметры через БД, то можно и сотни тысяч переварить.
Я про то, что типовой вопрос С-шника, программирующего СУБД на SQL это "а как тут цикл организовать?" .. нету циклов в реляционной алгебре от слова "совсем" .. и разные "курсоры" и прочие "навороты" в конкретных релизах - есть КОСТЫЛИ тем, кто не может решать задачи реляционной алгебры .. то бишь "вывернуть мозг" от алгоритмическго языка к реляциям. Равно как и явных (циклических) сортировок нет. Есть один единственный ORDER BY и что там лежит под ним, и каким набором циклов реализован SELECT .. реляционщику "по-барабану". И то, что "правильно" у реляционщика .. ровно наоборот у С-шника.
А ваш выбор "способный писать правильно", в смысле "без ошибок" .. как раз и есть ОПТИМАЛЬНОЕ программирование с использованием красивых решений и уже "типовых" алгоритмов. То есть - тавтология.
И, перечитайте себя: "я не рекомендую использовать глобальные переменные" .. это по-вашему правильно тут, в программировании микроконтроллеров? Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах! И после этого вы побежите покупать "побольше и помощнее" .. так и НЕ научившись программировать микроконтроллеры.
Это я и называю "а потом мы вам водичку нальем", а Вы пока потренируйтесь прыгать в пустой бассейн. :)
"Удивительные люди! Чесслово!"
Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах!
А пруф где? Или хотя бы аргументы?
Объясняю. Для того, чтобы обратиться к глобальной переменной есть два варианта:
1. Загрузить ее адрес в регистр X, Y или Z, а только потом обратиться к переменной.
2. Загрузить в регистра X, Y или Z начало сегмента статических переменных и адресоваться через смещение от регистра ко всем глобальным переменным не перезагружая адрес. Но это пройдет только в том случае, если общий объем глобальных переменных меньше 64 байт.
То же самое относится и к параметрам функции, но только там речь идет об указателе стека. И если объем глобальных переменных легко представить более, чем 64 байта, то для параметров одной функции это уже редкость.
Итого, сэкономив 2 байта в стеке на адрес переменной, увеличиваем расход памяти программ, да еще и понижаем быстродействие. И это при том, что расширить оперативную память для AVR возможностей полно, а программную - нет.
Вот, вот .. начинается. :) Вы случаем AVR с пиками не попутали? Тут, по секрету, есть прямая адресация глобала из команды. Все 64кб адресов и 2 слова программы (1 команда, 2 такта). Может, все-таки изучить матчасть, вместо предложения обучения "сферическим коням в вакууме"? .. это собственно и есть то, про что пишу: детскому самокату не требуется гидравлика. Она ему ПРОТИВОПОКАЗАНА. :)
Мдя. ptr, вы действительно верите в чушь которую вы тут выложили или вы просто неистово троллите Arhat109-2?
Но по любому, попкорном стоит запастись. ))))))))
есть прямая адресация глобала из команды
Пруф?
Мне стало жутко интересно, как в 16-ти битную команду удалось впихнуть и код команды и 16-ти битный адрес )
Пруф?
Мне стало жутко интересно, как в 16-ти битную команду удалось впихнуть и код команды и 16-ти битный адрес )
Уточню, меня интересует именно 16-ти битный вариант команды, так как 32-х битный доступен вовсе не во всех AVR.
А если речь идет именно о 32-х битной команде, то это уже потеря двух байт в программной памяти, ради выигрыша 2 байт в стеке )
Ок. Давайте по порядку. Ваш совет "глобалы == зло" подразумевает для AVR и микроконтроллеров "в целом" (есть конечно нюансы, но несущественно):
1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.
Ситуацию с "уже в регистре" не рассматриваем, поскольку локалов типа long можно считать "как таковых нет", это с одной стороны. А с другой стороны, если весь код повально делается с истреблением глобалов, то практически ВСЁ размещено в памяти. Ибо на все функции регистров не хватит - гарантировано. б) подпрограмный переход, с сохранением точки возврата, который есть в любом случае модульного программирования (функции).
Среднее количество параметров в функциях = 3.5, средний используемый тип 2.5 байта. Для новичков, в целях перестраховки берем 4 байта, хотя бы потому, что любимый millis() возвращает long. Итого, только на вызов функции тратится 3.5 * 4 = 14 байт стека и 3.5*16/32 <24>(в среднем) = <84> байта флеша для кода подготовки вызова. Кроме этого, функция имеет локалы .. их среднее количество также 3.5, и для типа long (напомню - это любимый тип всех начинающих) на регистрах будет только 1 переменная .. итого 2.5 * 4 = 10 байт плюсом из стека "долой". Ещё кроме этого, средняя функция сохраняет 3-4 (long!) регистра из пула "локальных" от предыдущего вызова .. пусть будет ещё пара байт.
Итого, средняя функция "программирования без глобалов" тянет на вызов 14 + 10 + 2 = 26 байт стека ПОМИМО хранения точки возврата. Плюс дополнительное время исполнения для примерно 50 команд из которых около трети в 2 такта.
Соответственно, "стека не хватит" определяется просто: делим имеющееся пространство стека на примерно 20-30 и смотрим допустимую глубину вложения вызовов рекомендуемого вами и автором опуса "ООП подхода". И это для средних, относительно простых функций. В случае "тяжелого кода" от новичка (типа классов Serial, Print и др.) этот показатель можно ускорить как миниум вдвое.
Неужели такую банальщину надо расписывать специалистам, берущимся ОБУЧАТЬ новичков?!?
Аналогично разбираются и ваши возражения предыдущего поста. Лично меня Вы уже смогли удивить и сильно .. :)
Да, кстати. Я ещё опустил рассмотрение вопроса ВОЗВРАТА результата функций обратно в вычисление и .. память. Так что, для "безглобального программирования микроконтроллеров" всё становится настолько печальным, что в пору бежать за "следующим поколением".. от неумения и догматического применения "рассово-правильного" подхода. :)
На самом деле "правилен" только один подход: оптимальное программирование. И оно .. РАЗНОЕ для каждого отдельного случая: SQL, десктоп, игры, сервера, транспьютеры и .. микроконтроллеры.
И до тех пор пока люди, берущие на себя ПРАВО ОБУЧАТЬ ДРУГИХ не начнут учить ХОРОШЕМУ .. надо чтобы хоть кто-то их останавливал в их стараниях учить плохому.
1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.
Не понял, мы перешли к обсуждению 32-х битных МК? При чем тут long? Если включить мозги, то вместо кучи глобальных и статических переменных, кроме одной глобальной, необходимой обработчикам прерываний, у нас будет одна переменная, указатель на которую мы и будем передавать вызываемым функциям. Handle это принято называть.
В связи с идеей, передавать функциям не хендл, а все по одному, да еще не указателями, а по значениям, все нижеследующее я удалю, чтобы не позорить оппонента.
чтобы не позорить оппонента.
Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)
Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)
Похоже пора завязывать, а то оппонент сейчас еще скажет, что одной глобальной переменной для всех обработчиков прерываний не хватит )
Причем с его страстью к оптимизации совершенно не ясно, почему он решил передавать параметры через стек, а не через регистры, что GCC вполне позволяет.
ptr, я заметил что не поняли. Ну да ладно .. со временем придет и понимание.
Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта. И напрямую применяют огульные рекомендации от "сферическими гуру", что называется "на веру". А равно "типовые библиотеки", писанные как правило программистами "общего профиля" .. то бишь для "сферических коней в вакуумах", один набор иерархии Serial чего стоит ... Вы полистайте форум таки.. :)
Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта.
Программировать на C без использования указателей невозможно. Даже
уже использование char *
И в третий раз повторю, в том числе и про новичков:
"Обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся"
где под "качественным" подразумевается "соблюдая ряд правил, которые позволяют минимизировать количество ошибок при написании программы".