<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-241211766593934532</id><updated>2011-07-07T20:29:01.862-07:00</updated><title type='text'>LabVIEW по-русски</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-241211766593934532.post-1664124698293260236</id><published>2010-06-28T07:46:00.000-07:00</published><updated>2010-06-29T22:17:36.014-07:00</updated><title type='text'>§ 5. О вызовах DLL из LabVIEW</title><content type='html'>LabVIEW — довольно высокоуровневая среда разработки. Работая с LabVIEW, мы не задумываемся о колоссальной работе компилятора, остающейся "за кадром". Мы просто соединяем &amp;nbsp;элементы друг с другом, совершенно не заботясь о том, как резервируются области памяти, как предаются параметры, что происходит в регистрах, и так далее. Кто сегодня может сказать, сколько регистров у процессора? Что происходит со стеком, как располагаются структуры в памяти? Однако рано или поздно любого программиста настигают ситуации, когда подобное знание необходимо. Одна из таких ситуаций — вызов DLL из кода LabVIEW. Когда требуется подключать сторонние DLL? Существует несколько типичных ситуаций:&lt;br /&gt;- производитель какого-либо устройства предоставил вам DLL для коммуникации&lt;br /&gt;- требуется использовать WinAPI, например для работы с окнами&lt;br /&gt;- ускорение критичных участков (LabVIEW довольно медленна сама по себе, как правило переписывание части кода на Си позволяет ускорить выполнение в несколько раз)&lt;br /&gt;&lt;br /&gt;Для упражнений нам помимо LabVIEW понадобится какой - либо компилятор, позволяющий скомпилировать код в DLL. Я пользуюсь компилятором CVI, также подойдёт VisualStudio (бесплатная Express в том числе). Я не буду описывать процесс создания DLL и пошаговое руководство по подключению DLL к LabVIEW, об этом вы можете прочитать на сайте NI, например в статье&amp;nbsp;&lt;a href="http://decibel.ni.com/content/docs/DOC-1690"&gt;Using Existing C Code or a DLL in LabVIEW&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Итак, начнём. Прежде всего надо заметить, что существуют два типа связи сторонних DLL с LabVIEW - статическая линковка и динамический вызов. В первом случае вы явно указываете имя и путь DLL в настройках. Во втором случае вы указываете путь к DLL на блок-диаграмме:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiv5b6yixI/AAAAAAAAARc/CRrm0GFTSLY/s1600/dll00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="188" src="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiv5b6yixI/AAAAAAAAARc/CRrm0GFTSLY/s400/dll00.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;В основном используется статическая связь. Однако вы не сможете запустить VI, если требуемая библиотека будет отсутствовать. В подобных случаях можно подгружать библиотеки динамически, при этом на загрузку библиотеки и поиск соответствующих функций потребуется некоторое время — вот маленькое исследование на эту тему &lt;a href="http://forums.ni.com/t5/LabVIEW/Dr-Damien-s-Development-Call-Library-Function-Node-Calling/m-p/1117773"&gt;Call Library Function Node Calling Optimization&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;А вот с чем имеет смысл досконально разобраться, так это с соглашениями о вызовах. Вы, вероятно уже заметили, что при подключении внешнего кода требуется установить флажок "Calling conventions":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/TCixb3S-FJI/AAAAAAAAARk/keUkiEazS7A/s1600/dll19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_V8YtjjvicV8/TCixb3S-FJI/AAAAAAAAARk/keUkiEazS7A/s320/dll19.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;А чем, собственно, отличаются "stdcall (WINAPI)" и "С"? Существует несколько соглашений о вызовах (stdcall, cdecl, thiscall, fastcall). Нас сейчас интересуют первые два (thiscall используется в С++, а fastcall — довольно редко). Наиболее часто используется cdecl (этому соглашению соответствует опция C), а stdcall в основном используется фирмой Микрософт как основное соглашение для вызовов WinAPI. Как правило по умолчанию в компиляторах включён режим cdecl.&lt;br /&gt;&lt;br /&gt;Давайте сделаем небольшую тестовую DLL, в которой исследуем то, каким образом передаются и возвращаются параметры, а также изучим различные соглашения о вызовах. Мы можем смело скомбинировать оба соглашения в рамках одной DLL, для этого напишем следующий код:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TChw1-ljuYI/AAAAAAAAAO8/oP-lLFX86rU/s1600/dll02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="203" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TChw1-ljuYI/AAAAAAAAAO8/oP-lLFX86rU/s400/dll02.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;Параметры в DLL можно передавать по значению или по ссылке. В вышеприведённом примере параметр In передаётся по значению, а параметр Out передаётся по ссылке (то есть передаётся не значение переменной, а адрес, по которому она находится). Подключение библиотеки выполняется следующим образом:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/TChx8sLlutI/AAAAAAAAAPE/HnJN73ru1Ig/s1600/dll03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="267" src="http://2.bp.blogspot.com/_V8YtjjvicV8/TChx8sLlutI/AAAAAAAAAPE/HnJN73ru1Ig/s400/dll03.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Обратите внимание на строку, где показывается прототип вызываемой функции — используйте эту строку для контроля правильности описания параметров:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/TChySlvLJYI/AAAAAAAAAPU/XFnL6n00bBM/s1600/dll04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="266" src="http://4.bp.blogspot.com/_V8YtjjvicV8/TChySlvLJYI/AAAAAAAAAPU/XFnL6n00bBM/s400/dll04.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Что же происходит "за кадром"? Давайте заглянем внутрь наших функций:&lt;br /&gt;&lt;br /&gt;Вот как выглядит функция, вызываемая как stdcall:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/TChzfgSrDEI/AAAAAAAAAPk/qwzzpiP7r00/s1600/dll06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="156" src="http://4.bp.blogspot.com/_V8YtjjvicV8/TChzfgSrDEI/AAAAAAAAAPk/qwzzpiP7r00/s400/dll06.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;А вот как выглядит функция, декларированная как cdecl:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/TChztT-mNxI/AAAAAAAAAPs/g2GqRd_UVp0/s1600/dll07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="148" src="http://2.bp.blogspot.com/_V8YtjjvicV8/TChztT-mNxI/AAAAAAAAAPs/g2GqRd_UVp0/s400/dll07.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Итак, как мы видим, происходит следующее:&lt;br /&gt;Параметры передаются через стек. Регистр esp - это и есть указатель на стек. Через стек передаются два аргумента. Параметр In смещён на четыре байта и его значение переносится из стека в регистр eax. Использование именно eax не случайно - это именно тот регистр, через который осуществляется возврат значения функцией (return In). Второй параметр Out смещён на восемь байт и его значение (при этом мы помним, что передали адрес) заносится в регистр edx. Третьей командой мы записываем значение eax по адресу, находящемуся в edx, затем возвращаемся в исходную программу. Вот здесь мы и видим отличие двух соглашений о вызовах. При вызове cdecl параметры заносятся в стек в обратном порядке, при этом указатель стека не изменяется (кстати, это даёт возможность вызывать функции с переменным количеством параметров, но не в LabVIEW). При вызове stdcall параметры передаются в прямом порядке, так как они объявлены в декларации, при этом указатель стека смещается на необходимое количество байт. В случае stdcall команда retn 8 выполняет коррекцию стека на 8 байт при выходе, а при использовании cdecl коррекция стека в теле функции не требуется. Что произойдёт в случае, если мы перепутаем соглашения? Мы получим неверный указатель стека при завешении функции, что в любом случае приведёт к проблемам. Дело даже не в возможной утечке памяти в стеке, а ещё и в том, что в стеке находятся другие данные, и неверный указатель практически моментально (или через некоторое время) приведёт к падению программы. Об этом также можно почитать в разделе помощи: &lt;a href="http://zone.ni.com/reference/en-XX/help/371361F-01/lvexcodeconcepts/configuring_the_clf_node/"&gt;Configuring the Call Library Function Node&lt;/a&gt;. И вот здесь мы натыкаемся на прелюбопытнейший эффект: программа продолжает работать как ни в чём не бывало даже в том случае, если мы неверно указали тип вызова! Оказывается, LabVIEW автоматически корректирует указатель стека даже в случае нашей ошибки. После нескольких экспериментов легко выяснить, что это происходит при установке флага Error Checking Level в Default (именно это значение и стоит по умолчанию):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiARQVObSI/AAAAAAAAAP0/KMk6dFR3auE/s1600/dll08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="266" src="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiARQVObSI/AAAAAAAAAP0/KMk6dFR3auE/s400/dll08.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Таким образом мы видим, что по всей вероятности LabVIEW сохраняет значение указателя стека перед вызовом функции, а затем проверяет значение после выхода из функции и выполняет автоматическую коррекцию в случае, если это необходимо (поскольку прототип вызываемой функции известен, а, следовательно известно и ожидаемое значение указателя стека после вызова). Заметьте, что никаких сообщений об ошибках при этом не выводится.&lt;br /&gt;&lt;br /&gt;Что произойдет в случае выбора других опций? Это легко выяснить:&lt;br /&gt;Disabled - приводит к немедленному падению LabVIEW, что и следовало ожидать&lt;br /&gt;Maximum - приводит к ошибке 1517:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiAzJ2ex2I/AAAAAAAAAP8/emx-3YJ1NR8/s1600/dll09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="181" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiAzJ2ex2I/AAAAAAAAAP8/emx-3YJ1NR8/s320/dll09.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Сообщение об ошибке в случае неверного типа функции &amp;nbsp;документировано, об этом можно почитать в статье&amp;nbsp;&lt;a href="http://zone.ni.com/reference/en-XX/help/371361F-01/lvdialog/call_lib_function_db/"&gt;Call Library Function Dialog Box&lt;/a&gt;. Таким образом следует обращать внимание на правильность указания соглашения о вызове. В случае неверного указания типа ошибку можно заметить не сразу, а например при изменении опции контроля ошибок.&lt;br /&gt;&lt;br /&gt;Ещё один вопрос, на который мы можем ответить — что произойдёт в том случае, если мы укажем, например, то, что фукнция возвращает значение, хотя на самом деле тип функции void, либо наоборот. В данном случае фатальных последствий не будет, так как возвращаемое значение просто записывается в регистр eax, так что в одном случае мы просто получим значение этого регистра, а в другом случае просто проигнорируем его. Утечек памяти и исключений не возникнет (пытливый читатель может разобраться с тем, что происходит при возврате восьмибайтовых типов или строки самостоятельно).&lt;br /&gt;&lt;br /&gt;Ещё одна из самых типичных ошибок — это неверное указание типа передаваемых параметров. В вышеприведённом примере наша функция имеет два параметра. Один из них (тот, который Out) передаётся по ссылке, и мы должны указать, что передаётся адрес переменной. Давайте намеренно совершим ошибку и передадим нулевое значение вместо адреса:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiEdTCSOxI/AAAAAAAAAQE/95rXf-_wCDo/s1600/dll10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="311" src="http://2.bp.blogspot.com/_V8YtjjvicV8/TCiEdTCSOxI/AAAAAAAAAQE/95rXf-_wCDo/s400/dll10.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Запись по нулевому адресу немедленно вызывает исключение, а вот внешнее проявление опять-таки зависит от опции Error Checking. В случае Maximum или Default результатом будет ошибка 1097:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/TCiFdzaGI4I/AAAAAAAAAQc/IWoQ6bJt4qY/s1600/dll11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="206" src="http://4.bp.blogspot.com/_V8YtjjvicV8/TCiFdzaGI4I/AAAAAAAAAQc/IWoQ6bJt4qY/s320/dll11.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;В случае, если мы выключим обработку ошибок вообще, то LabVIEW "упадёт". Таким образом, включение обработчика ошибок приводит также и к включению внутреннего обработчика исключений (примерно также, как это делается в C++ секциями try... catch).&lt;br /&gt;&lt;br /&gt;Побаловавшись с простыми типами, можно перейти к массивам. В простейшем случае мы просто передаём в функцию указатель на массив. Давайте попробуем сделать простое поэлементное копирование массивов:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiPgSQZlyI/AAAAAAAAAQk/Xtb3CZRLV8c/s1600/dll12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="103" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiPgSQZlyI/AAAAAAAAAQk/Xtb3CZRLV8c/s400/dll12.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;Здесь важно понимать то, что функция понятия не имеет о размере передаваемых массивов, так что количество копируемых элементов надо явно указать как параметр и передавать извне. Кроме того надо обратить внимание на то, что память под массив надо резервировать снаружи, в LabVIEW:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiQaaIpZ6I/AAAAAAAAAQ8/8JcFA5SDKUo/s1600/dll14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="386" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiQaaIpZ6I/AAAAAAAAAQ8/8JcFA5SDKUo/s400/dll14.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Типичная ошибка, которую можно совершить — выход за пределы массива. Как правило это приводит к исключению, либо нарушению работоспособности программы. Здесь снова может помочь включение режима отлова ошибок на максимум - в этом случае LabVIEW сообщить вам то, что вы выскочили за пределы массива (впрочем это не всегда спасает её от падения).&amp;nbsp;Возникает логичный вопрос — а нельзя ли передать одновременно с массивом и количество элементов, а также зарезервировать память внутри DLL? Это сделать можно, но перед рассмотрением этого вопроса имеет смысл поэкспериментировать с простыми структурами, так как у LabVIEW есть одна небольшая тонкость.&lt;br /&gt;&lt;br /&gt;Сделаем следующий пример:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiecsOAROI/AAAAAAAAARE/0EP8Ua9GNAs/s1600/dll15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="167" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiecsOAROI/AAAAAAAAARE/0EP8Ua9GNAs/s400/dll15.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Структурам в Си отвечает кластер в LabVIEW, но типичнейшая ошибка, которую как правило совершает начинающий программист, выглядит примерно вот так:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/TCifH5sCueI/AAAAAAAAARM/5Z1jZDNz8eM/s1600/dll16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="311" src="http://4.bp.blogspot.com/_V8YtjjvicV8/TCifH5sCueI/AAAAAAAAARM/5Z1jZDNz8eM/s400/dll16.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;В лучшем случае результат далёк от ожидаемого, а в худшем код вызывает исключение.&lt;br /&gt;Как же правильно передать структуру (читай - кластер) в DLL и обратно? Для этого нужно разобраться с тем, как хранятся данные в кластерах LabVIEW и в структурах Си. Основной документ, с которого имеет смысл начать —&amp;nbsp;&lt;a href="http://zone.ni.com/reference/en-XX/help/371361F-01/lvconcepts/how_labview_stores_data_in_memory/"&gt;How LabVIEW Stores Data in Memory&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;При передаче кластера в DLL мы фактически передаём указатель на адрес памяти, в котором хранится наш кластер. DLL принимает этот адрес и обращается к элементам структуры. Очевидно то, что реальное размешение кластера в памяти должно с точностью до байта отвечать ожидаемому расположению элементов в структуре.&lt;br /&gt;&lt;br /&gt;Прежде всего надо заметить, что массивы, строки и пути не хранятся непосредственно в кластере LabVIEW. Вместо них хранятся адреса (причём не на непосредственно данные, а на заголовки). Таким образом в приведённом примере передача массива или строки в составе кластера смысла не имеет. Поскольку массив в нашем примере хранится непосредственно в структуре, то и передавать его надо поэлементно. Здесь нас подстерегает ещё одна опасность. Каков размер структуры в Си (тот, что возвращает sizeof(TD_MyStruct))? Если вы думаете, что 13 байт (int + char + 2 x int = 4 + 1 + 2 x 4), то вы ошибётесь. Дело в том, что между членами char и int "вставлено" три дополнительных байта, которых вы не видите. Это сделано для исключения пенальти при обращении по адресам, невыровненным на границу 32х бит. Примеры выравнивания в структурах можно посмотреть в msdn: &lt;a href="http://msdn.microsoft.com/en-us/library/71kf49f1(v=VS.80).aspx"&gt;Structure Alignment Examples&lt;/a&gt;. По умолчанию установлено выравнивание на границу 4 байт, так что истинный размер структуры в нашем примере не 13, а 16 байт. А вот в LabVIEW элементы кластеров хранятся без выравнивания. Чтобы решить проблему выравнивания, существуют два пути - либо вставить недостающие "padding" элементы в кластер (это может быть использовано в том случае, если DLL не может быть перекомпилирована):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiqYYvVjMI/AAAAAAAAARU/36z-PcxhbIM/s1600/dll18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="456" src="http://1.bp.blogspot.com/_V8YtjjvicV8/TCiqYYvVjMI/AAAAAAAAARU/36z-PcxhbIM/s640/dll18.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;либо явно указать компилятору что наша структура не требует выравнивания (это достигается при помощи #pragma pack(1) непосредственно перед объявлением структуры). Обратите внимание, что&amp;nbsp;#pragma pack(1) будет распространяться на все структуры до момента пока не встретится следующая&amp;nbsp;#pragma pack.&lt;br /&gt;&lt;br /&gt;В заключение - маленький совет. Поскольку порядок следования элементов в кластере весьма важен, то для того, чтобы не проверять каждый раз порядок через меню "Reorder Elements in Cluster" просто установите опцию Arrange Vertically (доступно в контекстном меню) — в этом случае расположение элементов в кластере всегда будет отражать реальный порядок следования.&lt;br /&gt;&lt;br /&gt;Вот собственно и всё, на что стоит обратить внимание при подключении стороннего кода из DLL в LabVIEW:&lt;br /&gt;- соглашение о вызовах (stdcall или cdecl)&lt;br /&gt;- передача параметров по ссылке или по значению&lt;br /&gt;- выравнивание в структурах и порядок следования элементов.&lt;br /&gt;&lt;br /&gt;За кадром пока что остались опции управления потоками исполнения (UI или любой поток), функции управления менеджером памяти LabVIEW из стороннего кода и функции обратного вызова при определённых событиях, но об этом как-нибудь в другой раз...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/241211766593934532-1664124698293260236?l=labview-rus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/1664124698293260236/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://labview-rus.blogspot.com/2010/06/5-dll-labview.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/1664124698293260236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/1664124698293260236'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/2010/06/5-dll-labview.html' title='§ 5. О вызовах DLL из LabVIEW'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_V8YtjjvicV8/TCiv5b6yixI/AAAAAAAAARc/CRrm0GFTSLY/s72-c/dll00.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-241211766593934532.post-7376675104602841313</id><published>2010-02-02T08:36:00.000-08:00</published><updated>2010-02-02T08:40:08.528-08:00</updated><title type='text'>§ 4. LabVIEW против С или гонка за лидером</title><content type='html'>Здравствуйте, коллеги!&lt;br /&gt;&lt;br /&gt;Сегодня ещё несколько слов о быстродействии LabVIEW программ. В предыдущем параграфе было показано то, что генерируемый LabVIEW код довольно "рыхлый". Как это отражается на быстродействии и есть ли резервы? Давайте разберёмся.&lt;br /&gt;&lt;br /&gt;В качестве простенького примера займёмся вычислением центра масс восьмибитной картинки. (если вы забыли, что такое центр масс или центроид, то загляните в Википедию: &lt;a href="http://en.wikipedia.org/wiki/Centroid"&gt;Centroid&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Center_of_mass"&gt;Center of Mass&lt;/a&gt;) Для теста возьмём картинку Лены в четверть мегапиксела.&amp;nbsp;В качестве референсного примера я воспользуюсь IMAQ Centroid из библиотеки IMAQ Vision:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hI1EHladI/AAAAAAAAAKU/fx3N-KH81fo/s1600-h/IMAQ+Centroid+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="187" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hI1EHladI/AAAAAAAAAKU/fx3N-KH81fo/s400/IMAQ+Centroid+BD.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Этот пример даст мне значение центра масс в точке (265.19, 247.43):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hI-TdMbrI/AAAAAAAAAKc/Wbr2oTTWjkg/s1600-h/IMAQ+Centroid+FP.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="276" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hI-TdMbrI/AAAAAAAAAKc/Wbr2oTTWjkg/s400/IMAQ+Centroid+FP.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Классическая схема вычисления примерно такая:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hJExMqkZI/AAAAAAAAAKk/do9INsK4E8M/s1600-h/I64+Centroid+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="275" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hJExMqkZI/AAAAAAAAAKk/do9INsK4E8M/s640/I64+Centroid+BD.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;Заметьте, что использование типа I64 в данном случае более чем оправдано, иначе возникнет переполнение.&lt;br /&gt;&lt;br /&gt;Сколько времени займёт вычисление? Приготовим простенький бенчмарк:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hJWS-s9hI/AAAAAAAAAKs/PyElrEQA3R0/s1600-h/I64+Centroid+Bench+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="241" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2hJWS-s9hI/AAAAAAAAAKs/PyElrEQA3R0/s640/I64+Centroid+Bench+BD.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;На моём компьютере получается 8 миллисекунд. Неплохо.&lt;br /&gt;&lt;br /&gt;Пример хорош тем, что даёт богатую пищу для размышлений. Что произойдёт, если перейти от целочисленого типа к DBL?&amp;nbsp;Давайте проверим:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hJtJsmEKI/AAAAAAAAAK8/8vJ6AyqJqXE/s1600-h/DBL+Centroid+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="252" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hJtJsmEKI/AAAAAAAAAK8/8vJ6AyqJqXE/s640/DBL+Centroid+BD.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Получилось 5.5 миллисекунд. Уже лучше.&lt;br /&gt;&lt;br /&gt;Немного потеряв в точности, можно перейти к типу SGL:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hKF1Qj38I/AAAAAAAAALE/YGAM-STVYyE/s1600-h/SGL+Centroid+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="254" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hKF1Qj38I/AAAAAAAAALE/YGAM-STVYyE/s640/SGL+Centroid+BD.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Теперь 3,75 миллисекунды.&lt;br /&gt;&lt;br /&gt;Хороший программист сразу предложит вариант улучшения, позволяющий избавиться от вложенного цикла, например такой:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2hKk-rIVyI/AAAAAAAAALM/n4dTmMcLC6o/s1600-h/SGL+Centroid+BD+v2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="262" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2hKk-rIVyI/AAAAAAAAALM/n4dTmMcLC6o/s640/SGL+Centroid+BD+v2.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Теперь получилось&amp;nbsp;3,25&amp;nbsp;миллисекунды. Что ж, на этом, пожалуй, остановимся. Строго говоря, можно попытаться совсем избавиться от арифметики с плавающей точкой и перейти к целочисленному типу, оставаясь при этом в рамках 32 бит, но это вызовет значительное усложнение кода (а выигрыш будет невелик).&lt;br /&gt;&lt;br /&gt;Давайте кардинально изменим подход и перепишем этот участок кода на чистом Си. К вопросу подойдём "в лоб", взяв за основу самый первый пример:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2hP44MIp6I/AAAAAAAAALU/-ek1gPsYld8/s1600-h/C+Centroid.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="283" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2hP44MIp6I/AAAAAAAAALU/-ek1gPsYld8/s640/C+Centroid.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Это замечательное упражнение также помогает попрактиковаться в передаче массива и кластера в DLL:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hQJjDIWBI/AAAAAAAAALc/MadJedRCFNs/s1600-h/Centroid+DLL+BD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hQJjDIWBI/AAAAAAAAALc/MadJedRCFNs/s320/Centroid+DLL+BD.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Технически я пользуюсь средой CVI, на которую навешан Интеловский компилятор.&lt;br /&gt;&lt;br /&gt;Что же получается?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hQaXrh0NI/AAAAAAAAALk/PBR-e0pbhKw/s1600-h/Centroid+DLL+Bench+DLL.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2hQaXrh0NI/AAAAAAAAALk/PBR-e0pbhKw/s640/Centroid+DLL+Bench+DLL.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;0,84 миллисекунды! Наш код работает вчетверо быстрее аналогичного LabVIEW кода, что и требовалось доказать. (Пытливый читатель может сравнить ассемблерные листинги обоих примеров).&lt;br /&gt;&lt;br /&gt;Достигли&amp;nbsp;ли мы&amp;nbsp;предела производительности? Конечно нет, ведь можно использовать факт наличия двух или более ядер (наш код пока что однопоточный), или использовать SIMD&amp;nbsp;комманды. Однако несмотря на&amp;nbsp;очевидный выигрыш, конечно, не&amp;nbsp;стоит бросаться и&amp;nbsp;тут&amp;nbsp;же переписывать куски кода на&amp;nbsp;Си. Отлаживать такой код на&amp;nbsp;порядок сложнее, да&amp;nbsp;и&amp;nbsp;при современном быстродействии компьютеров как правило в&amp;nbsp;этом нет нужды. Рассматривайте эту возможность как резерв, который всегда есть, и&amp;nbsp;который можно и&amp;nbsp;нужно использовать при необходимости. А&amp;nbsp;«ранняя оптимизация»&amp;nbsp;— она, как правило, вредна и&amp;nbsp;порой приводит к&amp;nbsp;неоправданному увеличению сложности. Сначала закончите и&amp;nbsp;отладьте функциональность кода, затем определите «узкие места», попытайтесь оптимизировать LabVIEW код, и&amp;nbsp;лишь потом используйте «тяжёлую артиллерию».&lt;br /&gt;&lt;br /&gt;До следующих встреч,&lt;br /&gt;&lt;br /&gt;Андрей.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://vi-lib.com/forForum/CentroidLVvsC.zip"&gt;CentroidLVvsC.zip (5MB)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/241211766593934532-7376675104602841313?l=labview-rus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/7376675104602841313/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://labview-rus.blogspot.com/2010/02/4-labview.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/7376675104602841313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/7376675104602841313'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/2010/02/4-labview.html' title='§ 4. LabVIEW против С или гонка за лидером'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_V8YtjjvicV8/S2hI1EHladI/AAAAAAAAAKU/fx3N-KH81fo/s72-c/IMAQ+Centroid+BD.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-241211766593934532.post-3776407997241340893</id><published>2010-01-28T15:35:00.000-08:00</published><updated>2010-01-28T15:35:03.924-08:00</updated><title type='text'>§ 3. Интерпретатор или компилятор?</title><content type='html'>&lt;div style="text-align: left;"&gt;Здравствуйте, коллеги!&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Сегодня — несколько слов о внутреннем устройстве файлов LabVIEW, плюс парочка "хакерских" упражнений.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Много лет назад, только начиная работать с LabVIEW, я был абсолютно уверен в том, что LabVIEW — интерпретатор, в чём-то отчасти похожий на Basic. Блок-диаграмма наверняка представлена в виде некоего дерева, которое интерпретируется средой выполнения. В пользу этого также говорило наличие увесистой Run-Time Engine, необходимой для запуска "скомпилированного" приложения, возможность "подсветки" кода при выполнении, наличие файлов VI "как есть" внутри скомпилированного приложения, ну и малая скорость выполнения по сравнению с компиляторами типа С или Delphi (впрочем и сегодня оставляющая желать много лучшего). Однако моя уверенность значительно пошатнулась после прочтения любопытной статьи, в которой был продемонстрирован ассемблерный листинг простенького цикла:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a href="http://www.ni.com/devzone/lvzone/dr_vi_archived6.htm"&gt;Inside LabVIEW - How the Compiler Works&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a href="http://zone.ni.com/devzone/cda/tut/p/id/5315"&gt;Assembly Review&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Но даже увидев реальный код, я был уверен, что код этот — результат работы классного интерпретатора, выдернутый из памяти приложения. Я даже попытался сбросить память LabVIEW-программы в дамп и деассемблировать его, да ничего хорошего из этого не вышло.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Желающим повозиться самостоятельно скажу сразу, что пытаться деассемблировать скомпилированную LabVIEW программу "в лоб", равно как и отдельные SubVI смысла не имеет.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Однако как любому ребёнку хочется заглянуть внутрь любимой игрушки, так и мне никак не давал покоя вопрос — как же всё-таки устроен VI и где же код?&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Что ж, давайте набросаем простенький код, например тот, который был приведён в статье выше:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IVlkcYFuI/AAAAAAAAAJc/W-4gZuO4OfU/s1600-h/bild%2B22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IVlkcYFuI/AAAAAAAAAJc/W-4gZuO4OfU/s320/bild%2B22.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;и заглянем внутрь обычным hex-просмотрщиком (я использую обыкновенный Far):&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;img alt="" border="0" height="460" id="BLOGGER_PHOTO_ID_5431568206194659842" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2DOgX-J0gI/AAAAAAAAAH0/Rc3vX5GsS7o/s640/Increment+hex.png" style="display: block; height: 288px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: left; width: 400px;" width="640" /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;среди двоичного мусора можно легко заметить осмысленные четырёхбуквенные теги: LVIN, VIDS, BDHP, FPHP, ICON, CONP и так далее. Нетрудно догадаться что BD и FP - отвечают за блок-диаграмму и переднюю панель соответственно. На самом деле структура файла VI практически идентична ресурсам Макинтоша (более подробно можно прочитать в Википедии: &lt;a href="http://en.wikipedia.org/wiki/Resource_fork"&gt;Resource fork&lt;/a&gt;). Оно и понятно — ведь самые первые версии LabVIEW выпускались исключительно для Mac, и хранить ресурсы было удобнее в формате самой операционной системы.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Уже морально приготовившись к написанию парсера, я наткнулся на роскошную функцию LabVIEW:REdLoadResFile, с помощью которой можно не только получить список ресурсов из VI, но и вытащить двоичные данные для каждого ресурса:&lt;br /&gt;&lt;/div&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5431572541997969362" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2DScwGN79I/AAAAAAAAAH8/xp0IHwTtIzQ/s400/LabVIEW-REdLoadResFile.png" style="cursor: pointer; display: block; height: 98px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: left; width: 134px;" /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Кстати, возьмите на заметку — эта функция может вытащить ресурсы не только из *.vi, но и из *.ctl файлов; кроме того её можно вызывать как из LabVIEW, так и из Run-Time Engine.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Пользоваться этой функцией можно примерно так:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5431575462419864610" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2DVGvhDnCI/AAAAAAAAAIM/_lIR9IDmDyA/s400/resources+list+2.png" style="cursor: pointer; display: block; height: 179px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: left; width: 400px;" /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;(Сниппет не выкладываю ввиду известных багов LabVIEW с кластерами и property node в сниппетах - ну да мы к багам в LabVIEW привычные)&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;А получится вот что:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5431576208101772514" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2DVyJZejOI/AAAAAAAAAIU/y9k5yXEOQbk/s400/resources+list+3.png" style="cursor: pointer; display: block; height: 400px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: left; width: 335px;" /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Тут мы видим, что в нашем простеньком VI находится порядка трёх десятков ресурсов. Пытливый читатель может попытаться проанализировать двоичные данные самостоятельно, нас же сейчас интересует один единственный ресурс с тегом VICD. Это и есть скомпилированный код. Небольшая тонкость заключается в том, что код (как и некоторые другие ресурсы) упакован алгоритмом zip (сигнатура начала архива хорошо видна после чётвёртого байта).&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Давайте извлечём и распакуем его:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IRMPaMtqI/AAAAAAAAAIc/FE60ZhgqUew/s1600-h/bild%2B21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="276" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IRMPaMtqI/AAAAAAAAAIc/FE60ZhgqUew/s640/bild%2B21.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;ZLIB Inflate взят из OpenG. На вышеприведённой диаграмме код извлекается из VI и сохраняется в *.bin файле.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Ну вот, теперь похоже на некое подобие кода:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2IS5Ugm4xI/AAAAAAAAAIk/vYataDO2TEI/s1600-h/code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="340" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2IS5Ugm4xI/AAAAAAAAAIk/vYataDO2TEI/s400/code.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Дальше собственно дело техники - нам потребуется подходящий дизассемблер. Кто-то предпочитает HIEW, а мне нравится IDA, тем более что старенькая версия абсолютно бесплатна. Скачать можно вот отсюда: &lt;a href="http://www.hex-rays.com/idapro/idadownfreeware.htm"&gt;Free IDA Disassembler&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;При открытии файла нас спросят про детали - отвечаем что файл двоичный:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IT0dHLZ9I/AAAAAAAAAI8/CmLx-l41VAQ/s1600-h/bild%2B24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IT0dHLZ9I/AAAAAAAAAI8/CmLx-l41VAQ/s400/bild%2B24.png" width="335" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Затем вопрос про режим деассемблирования:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2ITwwtw9yI/AAAAAAAAAIs/y13SeZba8MM/s1600-h/bild%2B25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2ITwwtw9yI/AAAAAAAAAIs/y13SeZba8MM/s320/bild%2B25.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Разумеется соглашаемся с предложением 32-битного режима.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Ещё маленькое напоминание о том, что точку входа найти не удалось и её придётся указать вручную:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2ITy5lGAUI/AAAAAAAAAI0/o5to_WOO9ss/s1600-h/bild%2B26.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2ITy5lGAUI/AAAAAAAAAI0/o5to_WOO9ss/s320/bild%2B26.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Вот почти и всё. Когда файл откроется в IDA его надо промотать немного, скажем до адреса 20, и нажать клавишу "С" для запуска анализатора:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IT2dGRadI/AAAAAAAAAJE/eFahRg0r4V0/s1600-h/bild%2B27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="201" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IT2dGRadI/AAAAAAAAAJE/eFahRg0r4V0/s400/bild%2B27.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;После этого получится вот что:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IT4jpObjI/AAAAAAAAAJM/z1D_gmH-aUI/s1600-h/bild%2B28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="496" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S2IT4jpObjI/AAAAAAAAAJM/z1D_gmH-aUI/s640/bild%2B28.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Между адресами 119...16A находится тело цикла. Сравнение и увеличение счётчика показаны на скриншоте. Напомню как выглядел исходный VI:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IVlkcYFuI/AAAAAAAAAJc/W-4gZuO4OfU/s1600-h/bild%2B22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IVlkcYFuI/AAAAAAAAAJc/W-4gZuO4OfU/s320/bild%2B22.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Нельзя сказать что сгенерированный код оптимален, но в принципе неплохо.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Давайте сделаем маленький эксперимент. Возьмём простенький VI с увеличением счётчика:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IXFzR7COI/AAAAAAAAAJk/QSCShTytgP4/s1600-h/original.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IXFzR7COI/AAAAAAAAAJk/QSCShTytgP4/s320/original.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;LabVIEW генерирует вот такой код:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXHh9PyHI/AAAAAAAAAJs/80Vy1KMVl9Y/s1600-h/original+(1).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="57" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXHh9PyHI/AAAAAAAAAJs/80Vy1KMVl9Y/s400/original+(1).png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Всё просто и логично.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Любопытно взглянуть что получится если перейти к типу I64:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://4.bp.blogspot.com/_V8YtjjvicV8/S2IXJLcTLmI/AAAAAAAAAJ0/eSlMviF8fkM/s1600-h/original+(2).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_V8YtjjvicV8/S2IXJLcTLmI/AAAAAAAAAJ0/eSlMviF8fkM/s320/original+(2).png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;А получится вот что:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXKu-LEiI/AAAAAAAAAJ8/L8MBS2aZHW8/s1600-h/original+(3).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="117" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXKu-LEiI/AAAAAAAAAJ8/L8MBS2aZHW8/s400/original+(3).png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;инкремент заменили на сложение с единицей, кроме того старшие и младшие байты обрабатываются отдельно. Мораль — целочисленный 64 бит тип обычно приводит к замедлению кода и им не надо пользоваться если он явно не нужен.&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Ну и наконец двойной инкремент:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a href="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXLyLaHjI/AAAAAAAAAKE/SI5GuCAJIIo/s1600-h/original+(4).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="91" src="http://2.bp.blogspot.com/_V8YtjjvicV8/S2IXLyLaHjI/AAAAAAAAAKE/SI5GuCAJIIo/s200/original+(4).png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;LabVIEW накомпилирует следующую конструкцию:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IXNTbJISI/AAAAAAAAAKM/UaoenWzjjNI/s1600-h/original+(5).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="118" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S2IXNTbJISI/AAAAAAAAAKM/UaoenWzjjNI/s400/original+(5).png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Сравните этот листинг с листингом для одинарного инкремента I32. Хорошо видно, как компилятор работает что называется "в лоб", вставляя совершенно ненужные пересылки из памяти в регистры (три операции mov между инкрементами абсолютно не нужны).&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Что можно извлечь из всего написанного?&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Прежде всего — LabVIEW действтельно компилятор, причём компилятор совершенно фантастический — ведь генерация кода происходит практически "на лету". Вы нажимаете кнопку Run - и программа немедленно запускается. Процесс компиляции прозрачен и незаметен. Такого, пожалуй, нет ни у одного самого продвинутого компилятора. Мало того, что скомпилированный код также вставляется в исходные файлы (он сохраняется в VI вместе с блок-диаграммой), так он ещё и упаковывается при этом! При запуске приложения код распаковывается "на лету" средствами Run-Time Engine.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Важно также понимать, что сохранив VI без блок-диаграммы мы оставляем в файле только скомпилированный код, который превратить обратно в блок-диаграмму уже невозможно.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Сам по себе скомпилированный код нельзя назвать оптимальным, и именно поэтому в большинстве случаев аналогичный по функциональности участок диаграммы, переписанный на Cи и скомпилированный в DLL будет работать быстрее "нативного" LabVIEW кода.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;В заключение - пара VI, использованных в статье:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul style="font-family: Arial, Helvetica, sans-serif !important; list-style-type: none; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;li style="color: #666666; font-family: Arial, Helvetica, sans-serif !important; font-size: 7pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 3px; padding-left: 0px; padding-right: 0px; padding-top: 3px;"&gt;&lt;a class="jive-icon-doctype-compressed" href="http://decibel.ni.com/content/servlet/JiveServlet/download/38-11845/Classic%20Code.vi.zip" style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: url(http://decibel.ni.com/content/images/jive-icon-doctype-compressed-16x16.gif); background-origin: initial; background-position: 0% 50%; background-repeat: no-repeat no-repeat; color: #065fa3; font-family: Arial, Helvetica, sans-serif !important; font-size: 8pt; margin-bottom: 0px; margin-left: 0px; margin-right: 3px; margin-top: 0px; padding-bottom: 2px; padding-left: 20px; padding-right: 0px; padding-top: 2px;"&gt;Classic Code.vi.zip&lt;/a&gt;&amp;nbsp;(5.2 K)&lt;/li&gt;&lt;li style="color: #666666; font-family: Arial, Helvetica, sans-serif !important; font-size: 7pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 3px; padding-left: 0px; padding-right: 0px; padding-top: 3px;"&gt;&lt;a class="jive-icon-doctype-compressed" href="http://decibel.ni.com/content/servlet/JiveServlet/download/38-11844/Code%20Extractor.vi.zip" style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: url(http://decibel.ni.com/content/images/jive-icon-doctype-compressed-16x16.gif); background-origin: initial; background-position: 0% 50%; background-repeat: no-repeat no-repeat; color: #065fa3; font-family: Arial, Helvetica, sans-serif !important; font-size: 8pt; margin-bottom: 0px; margin-left: 0px; margin-right: 3px; margin-top: 0px; padding-bottom: 2px; padding-left: 20px; padding-right: 0px; padding-top: 2px;"&gt;Code Extractor.vi.zip&lt;/a&gt;&amp;nbsp;(13.4 K)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span style="color: black; font-family: 'Times New Roman';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span style="color: #666666; font-family: Arial, Helvetica, sans-serif; font-size: xx-small;"&gt;&lt;span class="Apple-style-span" style="font-size: 9px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/241211766593934532-3776407997241340893?l=labview-rus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/3776407997241340893/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://labview-rus.blogspot.com/2010/01/3.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/3776407997241340893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/3776407997241340893'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/2010/01/3.html' title='§ 3. Интерпретатор или компилятор?'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_V8YtjjvicV8/S2IVlkcYFuI/AAAAAAAAAJc/W-4gZuO4OfU/s72-c/bild%2B22.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-241211766593934532.post-8230974561554122849</id><published>2010-01-22T15:23:00.000-08:00</published><updated>2010-01-23T11:31:34.238-08:00</updated><title type='text'>§ 2. Об автоматической обработке ошибок</title><content type='html'>В LabVIEW есть пара опций, которые обычно отключают (хотя они включены по умолчанию):&lt;p align="left"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 123px;" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S1o0N5ZbcOI/AAAAAAAAAHU/wNy1E-OnA1I/s400/err11.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5429709714098974946" /&gt;&lt;/p&gt;&lt;p&gt;Суть автоматической обработки ошибок заключается в том, что при возникновении ошибки на выходе VI исполнение программы может быть остановлено (за диалог отвечает как раз вторая опция):&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 354px; height: 301px;" src="http://1.bp.blogspot.com/_V8YtjjvicV8/S1o0t3Sl_6I/AAAAAAAAAHc/YM4Sz3oWXEs/s400/err10.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5429710263289249698" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;В вышеприведённом примере мы создаём новую папку, но такая папка уже существует, что и вызывает ошибку 10 (если у вас нет папки Windows на диске с:\ просто запустите этот пример дважды). Поскольку выход примитива CreateFolder не подсоединён, то возникающая ошибка вызывает прерывание выполнения программы.&lt;/p&gt;&lt;p&gt;В следующем примере это дилоговое окно не появится:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 244px;" src="http://3.bp.blogspot.com/_V8YtjjvicV8/S1snhJhFcFI/AAAAAAAAAHk/003NkpBO5qE/s400/err12.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5429977226169118802" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;В ряде случаев подобные сообщения мешают. Например в вышеприведённом примере теоретически надо проверять код возврата для того, чтобы выяснить причину ошибки — либо папка уже существует, либо её создание невозможно по каким-либо причинам (например, недопустимая буква диска, либо нет прав на создание, либо недопустимые символы в имени и т.п.). При "первых набросках" или прототипировании программы проще отключить мешающие сообщения и не проверять ошибки типа описанной выше (большинство программистов — оптимисты и считают, что после вызова CreateFolder требуемая папка непременно будет создана если её ещё не существует).&lt;/p&gt;&lt;p&gt;Однако на заключительном этапе имеет смысл включить эту опцию и вычистить участки кода,  вызывающие "оборванные" ошибки (ну или как минимум обратить внимание на такие места).&lt;/p&gt;&lt;p&gt;Важно также не лениться (вы, конечно, можете просто соединить выход с блишайшей границей цикла или последовательности). Если вы не готовы принять решение о логике обработки какой-то конкретной ошибки немедленно, то лучше сделать SubVI со входом ошибки и подосединить его к выходу ошибки в "проблемном" месте. Внутри этого SubVI вы можете организовать запись в лог-файл или в лог отладки (более детально мы это рассмотрим в другом параграфе). Таким образом вы всегда сможете найти места в программе, где проблема пока не устранена (кстати, это будет работать и в исполняемом приложении).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/241211766593934532-8230974561554122849?l=labview-rus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/8230974561554122849/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://labview-rus.blogspot.com/2010/01/2.html#comment-form' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/8230974561554122849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/8230974561554122849'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/2010/01/2.html' title='§ 2. Об автоматической обработке ошибок'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_V8YtjjvicV8/S1o0N5ZbcOI/AAAAAAAAAHU/wNy1E-OnA1I/s72-c/err11.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-241211766593934532.post-7116619620241604510</id><published>2010-01-22T14:14:00.000-08:00</published><updated>2010-02-02T04:41:32.737-08:00</updated><title type='text'>§ 1. Что отличает профессионала от любителя</title><content type='html'>Запомните простую вещь — профессионал никогда не напишет «Labview» или «LabView» или как-либо ещё.&lt;br /&gt;&lt;br /&gt;Единственно верное написание — «LabVIEW». Только так и никак иначе.&lt;br /&gt;&lt;br /&gt;Тем не менее, даже если вы пишете «LabVIEW» правильно, то это ещё не делает вас профессионалом.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/241211766593934532-7116619620241604510?l=labview-rus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://labview-rus.blogspot.com/feeds/7116619620241604510/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://labview-rus.blogspot.com/2010/01/1.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/7116619620241604510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/241211766593934532/posts/default/7116619620241604510'/><link rel='alternate' type='text/html' href='http://labview-rus.blogspot.com/2010/01/1.html' title='§ 1. Что отличает профессионала от любителя'/><author><name>Andrey Dmitriev</name><uri>http://www.blogger.com/profile/08932813024277555288</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
