Телескопы покупают здесь


A A A A Автор Тема: Платформа Arduino: полезные советы и решения  (Прочитано 4867 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Платформа Arduino стала популярной как простенькая недорогая открытая платформа с большим количеством приферии с библиотеками, которую удобно программировать на С++ (ну, почти, с некоторыми отрезанными вещами).
Я предлагаю здесь собирать всякие полезные советы или универсальные решения уровня выше Tutorial-а, которые могут быть полезными для разработки на базе Arduino.

У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Итак, начнём, так сказать, с затравочки.

Всем, кто работал с платформой, известно, что есть официальная среда разработки, достаточно простенькая и неудобная: подсветка синтаксиса у неё только самая базовая, автодополнения нет, автоформатирование есть, но как будто для галочки.
Есть плагин для MS Visual Studio - Visual Micro, который позволяет создавать проекты для Arduino.
Ему для работы нужна установленная среда разработки Arduino (плагин пользуется её toolchain-ом).
Есть бесплатная версия, которая имеет некоторые ограничения.
Точно знаю, что есть возможность вести разработку по Eclipse и XCode, но сам не сталкивался - не было необходимости. Если у кого-то был опыт - прошу поделиться.
А вообще их много: http://playground.arduino.cc/Main/DevelopmentTools
« Последнее редактирование: 03 Июл 2016 [20:52:41] от Deimos »
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Язык С++ не стоит на месте и компилятор для Arduino поддерживает стандарт C++11, однако чтобы его включить, нужно поменять кое-какие настройки. Для этого нужно открыть файл hardware\arduino\avr\platform.txt из каталога установки Arduino, найти параметр compiler.cpp.flags и добавить в конце флаг -std=gnu++11. Там же можно выставить настройки оптимизации.
У меня строка выглядит вот так:
compiler.cpp.flags=-c -g -Ofast {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -std=gnu++11
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Проект компилируется в промежуточный каталог
%userprofile%\AppData\Local\V.Micro\Arduino\Builds\<имя-проекта>\<имя-платы>
Можно добавить дополнительные действия после завершения компиляции проекта.
Для этого надо создать post-build event, записав в файле platform.txt (см. предыдущее сообщение) строку
recipe.hooks.postbuild.0.pattern=<выполняемый файл>Например я сделал так:
recipe.hooks.postbuild.0.pattern="{compiler.path}stat.bat" "{build.path}/{build.project_name}"То есть запускает из пути, где лежит компилятор С++, файл stat.bat, и параметром ему передаётся путь к каталогу сборки и имя (без расширения - мы его позже сделаем как нам надо).
Файл stat.bat я создал сам, его надо положить сюда:
hardware\tools\avr\bin\stat.bat
Содержимое его весьма нехитрое:
%~dp0\avr-objdump.exe -d -C %1.elf > %1.SX
%~dp0\avr-nm.exe %1.elf -nCS > %1.names.txt
Первая строка дизассемблирует полученный .elf-файл в одноимённый файл с расширением .SX, и это позволяет ознакомиться с тем, что же наделал комплятор с нашим проектом. Вторая строка извлекает в файл с расширением .names.txt все переменные, функции и т.д. с размерами и распределением по адресному пространству.
Диапазон адресов начиная с 0 - секция .text (код функций), начиная с 00800200 - сначала .data (инициализированные данные), затем .bss (неинициализированные данные). Символы __bss_start и __data_end указывают на адрес, где заканчиваются инициализированные данные и начинаются неинициализированные; __bss_end указывает на конец всех данных.
Если в проекте используется динамическое выделение памяти (что оооооочень плохо), то дальше идёт куча, которая растёт в сторону увеличения адресов, а навстречу ей начиная с адреса RAMEND и в сторону уменьшения адресов идёт стек.
У Arduino нет никаких средств слежения за правильностью использования памяти, поэтому лучше не допускать ситуации, когда данные занимают практически всю память, потому что значения стека могут быть записаны поверх данных, что, понятное дело, в лучшем случае приведёт к странным глюкам, в худшем может отправить счётчик адресов куда-нибудь в очень неожиданное место, и отлаживать такое - не самое большое удовольствие.

Конечно, эта штука нужна далеко не каждому, но если есть желание иметь полный контроль над тем, что выдаёт компилятор - это может быть полезно.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Чуть позже опишу опыт тюнинга стандартных библиотек, имитацию на Arduino многопоточности, а также систему сбора телеметрии о работе устройства.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Продолжаю вещание ;D

Предполагаем, что читатели этой темы как минимум представляют, как писать маленькие скетчи, которые делают своё дело, но хотят начать работать с чем-то покрупнее, но не знают, как к этому подступиться. Начинаем тему параллельной независимой работы с большим количеством периферии :)

Но начнём с матчасти, а именно о том, что такое многозадачность, какая она бывает, как реализуется и при чём тут вообще платформа Arduino.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Задача - это логическая единица в программной системе, которая характеризуется последовательностью операторов, составляющих программный код, а также состояние, которое включает глобальные переменные, стек и регистры процессора. То есть проще говоря, задача - это код, который манипулирует данными и в каждый момент времени может быть описан текущим состоянием.
В простейшем случае на процессоре/контроллере выполняется одна задача. Применительно к платформе Arduino - это и есть скетч.
Когда система становится сложнее, контекст выполнения начинает разделяться на множество логических задач, которые могут работать независимо и параллельно, но есть один ресурс, которым владеть может только один владелец - это вычислительное ядро процессора. Оно может выполнять только одну последовательность инструкций. Как же организовать параллельность? То есть реализовать работу нескольких задач, которые по очереди получали какое-то время владения процессором, после чего происходило переключение задач. Разумеется, нужна какая-то низкоуровневая инфраструктура, которая в зависимости от сложности обычно называется операционной средой или операционной системой.
Построенная по классической схеме операционная среда состоит из ряда ключевых компонентов:
* диспетчер задач, который отвечает за создание, завершение и планирование выполнения задач
* диспетчер ресурсов, который отвечает за выделение, владение и освобождение таких ресурсов, как память, адресное пространство ввода-вывода, доступ к периферийным устройствам и т.п.
* средства межпроцессного взаимодействия и синхронизации
* различные библиотеки операционной системы с наборами функций.

По сути Arduino нам даёт только набор библиотек функций для доступа к периферии, таймерам и т.п.

Если пойти дальше, то хочется иметь защиту задач друг от друга и операционной среды от задачи, и это можно сделать двумя способами:
* Аппаратная защита, когда необходимые инструменты реализуются с помощью аппаратных средств процессора
* Использовать виртуализацию выполнения, когда виртуальная машина выполняет байт-код своим интерпретатором, а язык, создающий этот байт-код, не имеет средств запрограммировать потенциально небезопасные операции.

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

Итак, предварительно поставим примерные задачи, которые хотим решить:
1. нам нужны средства описания задач. Желательно, чтобы описание задачи было кратким.
2. нам нужны средства диспетчеризации задач, включая создание, удаление и переключение. Крайне желательно, чтобы код был эффективным.
3. нам желательно иметь средства владения аппаратными ресурсами, но это на первых порах не обязательно.
4. у нас есть библиотечные функции, и надо понять, какие из них мы можем использовать и какие пригодны для нас.

И, наконец, нам надо определиться с ограничениями, в которых мы будем работать, а также иметь диагностические средства для контроля ресурсов.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Чтобы двигаться дальше, надо разобраться, как же идёт переключение задач в операционной системе. Для простоты считаем, что задачи (процессы) имеют ровно один поток и мы не будем рассматривать подкачку данных, по крайней мере пока.
Итак, что задача - это:
* секция исполняемого кода
* стек
* состояние регистров
* набор данных в оперативной памяти
Для того, чтобы операционная система переключила поток, нужно сначала выбрать поток, на который следует переключиться (алгоритмы выбора рассмотрим позже), а затем выполнила следующую последовательность действий:
* приостановить выполнение кода и сохранить адрес инструкции, с которой надо будет начать выполнение
* куда-то сохранить значение регистров. Это может быть либо стек задачи, либо специальная область памяти, однозначно сопоставляемая с задачей.
* восстановить значене регистров возобновляемой задачи
* получить значение адреса, которому надо передать управление в возобновляемой задаче
* перейти по полученному адресу
В теории всё хорошо, но на практике надо хранить все регистры общего назначения и парочку регистров специального назначения, что для Arduino составляет примерно 36 байт на каждую задачу. Кроме того, регистры нужны не только задаче, но и операционной среде для манипуляции данными. На языке высокого уровня такое писать без привлечения ассемблера никак не выйдет, поэтому мы пойдём по другому пути, вводя адекватные упрощения.
И ещё один момент, которого необходимо коснуться: когда же запускается код планировщика, инициирующий вытеснение задачи? Вот типичные ситуации, когда это происходит:
* вызов блокирующей функции ввода-вывода
* одижание освобождения объекта синхронизации, перехода объекта синхронизации в сигнальное состояние, или вызов функции задержки (вроде sleep)
* обработчик прерывания завершения ввода-вывода, таймера или какого-либо внешнего события, которое может привести к необходимости пробуждения какой-либо задачи.
« Последнее редактирование: 16 Июл 2016 [16:39:09] от Deimos »
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Двигаемся дальше. У нас появилось такое понятие, как объект синхронизации. Давайте разберёмся, что это такое и зачем оно надо.
Есть ресурсы, которые не могут быть произвольным образом разделены между процессами, например интерфейсы ввода-вывода (например, на шине I2C висит несколько устройств, но одновременно можно взаимодействовать только с одним из них), или структуры данных, которые не могут быть изменены параллельными потоками произвольным образом, и надо чтобы какие-то действия выполнялись целиком (например надо записать значение в одну ячейку и увеличить на 1 значение в другой ячейке при реализации FIFO). В этом случае необходимо использовать техники, которые исключат некорректный доступ к ресурсам.
Или может быть ситуация, когда произошло внешнее событие, и об этом необходимо уведомить тех, кто заинтересован в получении такой информации (пример - нажатие кнопки или окончание длительного рассчёта).
Мы пока не будем вдаваться сильно в подробности всего этого, но когда дело дойдёт до реализации, мы всё это поддержим.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Давайте посмотрим теперь, что же у нас есть из ресурсов на Arduino и что с этим можно делать. А ресурсы очень скромные:
32 килобайта Flash-памяти для кода на большинстве плат, 128 или 256 килобайт на "толстых" платах Arduino Mega, и это на все задачи, и часть этого объёма занимает загрузчик.
2-2,5 килобайта SRAM (оперативной памяти) или 8 килобайт на Arduino Mega
1-2 килобайта EEPROM, но это нам не сильно интересно сейчас.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
(Интересно, этот поток сознания вообще кто-то читает? Это кому-нибудь надо?)
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

andreichk

  • Гость
тебе надо - ты и читай.... ;D

Оффлайн 1212Lupus

  • *****
  • Сообщений: 3 094
  • Благодарностей: 196
  • Мне стал не очень нравиться этот форум...
    • Сообщения от 1212Lupus
    • http://belastro.net
Читают, но написано тяжеловато. Для новичков переваривается с трудом.
Радиоастрономы-любители -- объединяемся!


Если утро наступает в три -
Через два часа уже зажгут фонари.
Уже кончился день, а я только встал,
А я только что встал и уже устал.
(с) НОЛЬ

alex AMK

  • Гость
(Интересно, этот поток сознания вообще кто-то читает? Это кому-нибудь надо?)
:) я читаю , сложновато, но  стимул для более глубокого вгрызания в этот гранит существенный. Интерес простой - заменить микрокомпьютер LX200GPS который нигде не купить, платой Ардуино.

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Ну, я изначально позиционировал тему для уже не новичков, но можно сделать отдельную тему для новичков.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн Дядя Вова

  • *****
  • Сообщений: 8 083
  • Благодарностей: 95
    • Сообщения от Дядя Вова
заменить микрокомпьютер LX200GPS который нигде не купить, платой Ардуино.
Дайте ссылочку на описание Вашей проблемы.
(Vixen ED80+Canon300Da, 9x50+QHY5)+EQ6upg
Meade ETX-90PE

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Сегодня поговорим о памяти :)

Память кода и память данных размещаются отдельно (так называемая гарвардская архитектура), и адресуются независимо. Адресное пространство кода содержит только код (есть оговорка по поводу хранимой в программной области данных, но об этом позже). Адресное пространство состоит из двух частей: младшие 0x200 (512) адресов - это адреса регистров, следующие адреса указывают на SRAM. Если объём SRAM составляет 2 килобайта, то адрес последней ячейки равен 512+2048-1=0x9FF, если 8 килобайт, то 512+8192-1=0x21FF
В начале SRAM располагаются инициализированные данные - то есть те глобальные, статические локальные переменные и статические поля классов, которым присвоено значение, а также объекты типов, имеющих нетривиальный конструктор (то есть имеется написанный явно конструктор класса).
Все эти переменные инициализируются до того, как начнёт выполнение функция main.
Далее идут неинициализированные данные - глобальные, статические локльные переменные и статичекие поля классов, которым значение не присвоено, и которые не имеют нетривиального конструктора. Все эти переменные будут заполнены значением 0 (false, 0.0, nullptr и т.п.)
Стек организован следующим образом: он начинается со старшего адреса в оперативной памяти и растёт в направлении уменьшения адресов. Добавление элемента в стек приводит к уменьшению указателя стека (stack pointer), извлечение из стека сопровождается увеличением значения указателя стека. Таким образом, рост стека приводит к тому, что указатель стека перемещается всё ближе и ближе к данным. Если использование стека превосходит объём памяти, оставшейся после данных, то стек затирает данные. Никакой проверки не происходит!
Если в программе динамически выделяется память с помощью вызова malloc/calloc/operator new, то используется память между данными и стеком, но предсказать её спользование становится более проблематичным, чем отслеживание размещения переменных. Кроме того, если часто выделяются/освобождаются области динамической памяти, то возникает проблема фрагментирования кучи (так называется область динамически размещаемых данных), что приводит к её разрастанию и потенциальному перекрытию со стеком. В любом случае, работа с динамической памятью во встраиваемых системах с малым объёмом памяти - это плохая идея.
Осталась самая странная и непонятная область памяти, называемая стек.
Он используется для поддержки вызовов функций. Когда вызывается некоторая функция, туда сначала записываются аргументы функции (если это метод - то неявный аргумент this тоже является аргументом функции), и выполняется машинная инструкция call <func>, которая записивает в стек адрес следующей инструкции, и выполняет переход по указанному адресу. Затем вызываемая функция выделяет в стеке место под все локальные переменные (но не иницализирует их - это важно!), сохраняет туда же регистры, которые не должны измениться после выхода из функции, и начинает выполнение собственно пользовательского кода. Полученная конструкция называется кадром стека (или фреймом - кому как больше нравится). Когда функция завершает работу, она смещает указатель стека на величину общего размера локальных переменных, и выполняет инструкцию ret, которая снимает со стека адрес возврата и переходит по нему, после чего вызывающая функция удаляет со стека переданные аргументы.
Когда выполняется вложенный вызов функции, формируется ещё один кадр стека. Получается, что вся цепочка вызовов, начиная от точки входа в программу, располагается на стеке.
Ещё один сценарий происходит при возникновении прерывания (если данное прерывание разрешено, и прерывания разрешены глобально в регистре флагов). Текущий выполняющийся код завершает выполнение текущей инструкции, после чего в стек записывается адрес инструкции, с которой нужно будет продолжить выполнение, и запрещаются другие прерывания. Дальше начинает выполняться обработчик этого прерывания, который представляет по сути обычную функцию, которая завершается не инструкцией ret, а инструкцией reti, которая отличается лишь тем, что разрешает прерывания после выхода. Если во время обработки прерывания возникло другое прерывание, то его обработка откладывается до завершения работы текущего.
Теперь можно сделать выводы относительно того, сколько же стека надо - максимум суммы фреймов стека из всех возможных в коде вариантов вызовов функций плюс максимальный фрейм обработчика прерывания.

У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн Михаил ФМ

  • **
  • Сообщений: 82
  • Благодарностей: 8
    • Сообщения от Михаил ФМ
В любом случае, работа с динамической памятью во встраиваемых системах с малым объёмом памяти - это плохая идея.
Передача родных массивов С в вызываемые функции через стек - вероятно, ещё более плохая идея ;). То же относится и к передаче функций в функции. Все компиляторы С/С++ гарантируют корректную передачу объектов через указатели, но конечно, программист обязан следить за расходом памяти. Дырки в куче - это ошибки программирования, наилучший практический способ их избежать (ну, почти избежать :)) - использовать STL (<vector>, <list> и т.п.), имхо.

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Передача родных массивов С в вызываемые функции через стек - вероятно, ещё более плохая идея ;).
Секундочку, я тут имел в виду, что куча растёт в сторону увеличения адресов, а стек - в сторону уменьшения, то есть друг другу навстречу. Когда столкнутся лбами - будет больно.

Далее, в зависимости от конвенции вызова часть аргументов могут передаваться через регистры. Если их мало - то все. А способ передачи возвращаемого значения в большинстве конвенций - это отдельный разговор.

На Arduino вообще не поддерживается STL, памяти мало. Есть одна стандартная библиотека - SD, где есть такая строка:
  _file = (SdFile *)malloc(sizeof(SdFile)); Непонятно зачем, но есть. Если будет перемежаться открытие файлов с выделением памяти где-то в пользовательском коде, уже может быть проблема.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/

Оффлайн xdАвтор темы

  • *****
  • Сообщений: 17 977
  • Благодарностей: 378
    • Skype - deimos.belastro.net
  • Награды Открытие комет, астероидов, сверхновых звезд, научно значимые исследования.
    • Сообщения от xd
    • Белорусская любительская астрономическая сеть
Поиск по исходникам стандартных библиотек дал 39 файлов, где используется malloc.
У природы нет плохой погоды, у неё просто на нас аллергия.

Учение без размышления бесполезно, но и размышление без учения опасно /Конфуций/
Слово есть поступок. /Л. Толстой/