<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; CMD/BAT: возврат значений из процедур через параметры]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=2944</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=2944&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «CMD/BAT: возврат значений из процедур через параметры».]]></description>
		<lastBuildDate>Wed, 19 Dec 2012 05:20:13 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: CMD/BAT: возврат значений из процедур через параметры]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=67139#p67139</link>
			<description><![CDATA[<p>Как заметил <strong>Arigato</strong>, результат функции, вычисляющей целочисленное значение, можно возвращать через код завершения <em>errorlevel</em>:<br /></p><div class="codebox"><pre><code>@echo off
setlocal enableextensions
set /p a=Enter a: 
call :sqr %a%
echo %a%^^2 = %errorlevel%
pause
endlocal
exit /b 0

:sqr
:: Квадрат числа %1
setlocal
set /a result=%1*%1
endlocal &amp; exit /b %result%</code></pre></div><p>(Таким образом можно возвращать целое 32-битное число со знаком, т.е. от -2147483648&nbsp; до 2147483647, иначе оно будет преобразовано к этому диапазону.)</p>]]></description>
			<author><![CDATA[null@example.com (wisgest)]]></author>
			<pubDate>Wed, 19 Dec 2012 05:20:13 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=67139#p67139</guid>
		</item>
		<item>
			<title><![CDATA[Re: CMD/BAT: возврат значений из процедур через параметры]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=42528#p42528</link>
			<description><![CDATA[<p>В ряде случаев, когда требуется одно возвращаемое процедурой значение, может оказаться удобным использовать для возврата этого значения не указанную параметром переменную окружения (как описано в предыдущем посте), а использовать для этого метку процедуры (получив «как бы функцию»), например:<br /></p><div class="codebox"><pre><code>@echo off
setlocal enableextensions enabledelayedexpansion

call :Double 5
echo Result of Double(): [%Double%]

endlocal
exit /b 0

:Double
    setlocal enableextensions enabledelayedexpansion
    set sOut=%~0
    set /a sResult = %~1 + %~1
    
    endlocal &amp; set %sOut:~1%=%sResult%
    exit /b</code></pre></div><div class="quotebox"><blockquote><div class="codebox"><pre><code>Result of Double(): [10]</code></pre></div></blockquote></div><p>Автор идеи — <strong>smaharbA</strong>.</p>]]></description>
			<author><![CDATA[null@example.com (alexii)]]></author>
			<pubDate>Sun, 05 Dec 2010 17:41:04 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=42528#p42528</guid>
		</item>
		<item>
			<title><![CDATA[CMD/BAT: возврат значений из процедур через параметры]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=20814#p20814</link>
			<description><![CDATA[<p>Как известно, командный процессор NT-систем позволяет организовать подобие процедур на основе меток внутри пакетного файла и вызова нового контекста пакетного файла (<a href="http://rsdn.ru/article/winshell/batanyca.xml#EDFAC">А можно создать в bat-файле функцию?</a>).</p><p><em>Использование процедур:</em><br /></p><div class="codebox"><pre><code>@echo off
setlocal enableextensions enabledelayedexpansion

set /a i=1
set /a j=2

call :Sub %i% %j%
echo i=%i%, j=%j%, k=%k%

endlocal
exit /b 0
rem ==========================================================================

rem ==========================================================================
:Sub
    set /a k=%1 + %2

    exit /b 0
rem ==========================================================================</code></pre></div><div class="quotebox"><blockquote><p>i=1, j=2, k=3</p></blockquote></div><p>Вызов процедуры производится с помощью команды «call», возврат из нового контекста в старый — командой «exit /b».</p><p>Но тут есть одна проблема: в новом контексте доступны все переменные среды старого контекста, что создаёт определённые проблемы. Можно, конечно, определить в процедуре собственный уровень локализации переменных среды командой «setlocal», однако при этом становятся недоступны все переменные среды «родительского» контекста, поскольку любая переменная будет являться локальной и будет существовать только внутри процедуры.</p><p><em>Переменная среды «k» является локальной для процедуры:</em><br /></p><div class="codebox"><pre><code>@echo off
setlocal enableextensions enabledelayedexpansion

set /a i=1
set /a j=2

call :Sub %i% %j%
echo i=%i%, j=%j%, k=%k%

endlocal
exit /b 0
rem ==========================================================================

rem ==========================================================================
:Sub
    setlocal enableextensions enabledelayedexpansion
    set /a k=%1 + %2

    endlocal
    exit /b 0
rem ==========================================================================</code></pre></div><div class="quotebox"><blockquote><p>i=1, j=2, k=</p></blockquote></div><p>Тем не менее, существует способ, позволяющий безболезненно использовать локальные переменные среды в процедуре и вместе с тем передавать значения в процедуру и возвращать значения в основную часть пакетного файла из процедуры.<br /></p><div class="codebox"><pre><code>@echo off
setlocal enableextensions enabledelayedexpansion

set /a i=1
set /a j=2

call :Sub %i% %j% k
echo i=%i%, j=%j%, k=%k%

endlocal
exit /b 0
rem ==========================================================================

rem ==========================================================================
:Sub
    setlocal enableextensions enabledelayedexpansion
    
    set /a Summa=%1 + %2
    
    endlocal &amp; set /a %3=%Summa%
    exit /b 0
rem ==========================================================================</code></pre></div><div class="quotebox"><blockquote><p>i=1, j=2, k=3</p></blockquote></div><p>Передача входных параметров в процедуру осуществляется стандартным образом с помощью команды «call :&lt;Метка процедуры&gt;»:<br /></p><div class="codebox"><pre><code>call :Sub %i% %j% …</code></pre></div><p>Выходные параметры указываются просто именем переменной:<br /></p><div class="codebox"><pre><code>call :Sub … k</code></pre></div><p>Возврат значений производится в одной строке с командой «endlocal» процедуры как «set &lt;номер параметра&gt;=&lt;значение&gt;»:<br /></p><div class="codebox"><pre><code>endlocal &amp; set /a %3=%Summa%</code></pre></div><p>Только так и не иначе. Что при этом происходит? А происходит следующее:<br />1. Строка разбирается командным процессором и происходит раскрытие переменных среды. Таким образом, вышеуказанная строка превращается в:<br /></p><div class="codebox"><pre><code>endlocal &amp; set /a k=3</code></pre></div><p>поскольку параметр «%3» раскрывается в строку «k», а переменная среды «%Summa%», находящаяся внутри процедуры «:Sub», раскрывается в её значение «3».<br />2. Исполняется первая команда в очереди команд:<br /></p><div class="codebox"><pre><code>endlocal</code></pre></div><p>При этом происходит закрытие локального контекста и становится доступным родительский контекст.<br />3. В родительском контексте исполняется вторая команда:<br /></p><div class="codebox"><pre><code>set /a k=3</code></pre></div><p>в результате чего переменная «k» получает значение «3».<br />4. Командой<br /></p><div class="codebox"><pre><code>exit /b …</code></pre></div><p>осуществляется возврат из процедуры.</p><br /><p><strong><em>Замечание:</em></strong></p><p>Чтобы стало понятнее, приведу несколько неправильных способов.<br /></p><div class="codebox"><pre><code>set /a k=%Summa%
endlocal</code></pre></div><p>В данном случае происходит присвоение значения локальной переменной «k», что никак не отразится на родительском контексте.</p><div class="codebox"><pre><code>set /a %3=%Summa%
endlocal</code></pre></div><p>То же самое. Параметр %3 раскрывается в значение «k», а результат исполнения команды «set /a k=…» мы рассмотрели чуть выше.</p><div class="codebox"><pre><code>endlocal
set /a %3=%Summa%</code></pre></div><p>Здесь переменная %Summa% из контекста процедуры уже не существует (в понимании командных файлов будет равна пустому значению), в результате чего данная команда выродится в «set /a k=». Но мы ведь не этого хотели, правда?</p><div class="codebox"><pre><code>set /a %3=%Summa% &amp; endlocal</code></pre></div><p>«А почему бы команды не поменять местами? Какая нам разница?» А вот какая. Вначале будет выполняться команда «set /a %3=%Summa%». После раскрытия переменных мы получим вроде бы ту же самую правильную команду «set /a k=3». Однако, в этот момент мы ещё находимся <strong>внутри локального контекста процедуры</strong>, и переменная «k» — тоже будет локальная. Значит, следующей командой («endlocal») эта переменная будет уничтожена. Вот почему такой способ тоже не годится.</p><p>Остаётся только добавить, что на данный метод я наткнулся, разбираясь со скриптом <a href="http://www.netikka.net/tsneti/info/tscmd032.htm">TSCMD032 FAQ: How can I convert a decimal number to binary, octal, hexadecimal? Assorted NT/2000/XP/.. CMD.EXE script tricks written by Timo Salmi</a>, в момент публикации обнаружилось, что на том же сайте существует и отдельная статья на эту тему: <a href="http://www.netikka.net/tsneti/info/tscmd018.htm">TSCMD018 FAQ: How does one build re-usable script function modules? Assorted NT/2000/XP/.. CMD.EXE script tricks written by Timo Salmi</a>.</p>]]></description>
			<author><![CDATA[null@example.com (alexii)]]></author>
			<pubDate>Thu, 19 Mar 2009 03:37:50 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=20814#p20814</guid>
		</item>
	</channel>
</rss>
