В языке программирования со статической областью видимости , например, в большинстве других языков программирования (, таких как C ),
Каждая функция имеет глобальную и локальную области действия. Переменные, появляющиеся в функции, являются либо частными для функции, либо глобальными.
Функция может обращаться только к своим локальным переменным или к глобальным переменным. Он не может получить доступ к переменным другой функции (, даже вызывающей ее функции ), кроме как через передачу по ссылке.
В языке программирования с динамической областью видимости ,
функция видит переменные своего вызывающего объекта, и для каждой функции вашего дерева вызовов есть область действия. Область видимости похожа на русские матрешки, где переменные накладываются друг на друга.
В этом стеке областей глобальная область действия отличается только тем, что она является самой нижней -самой, но функции не обязательно видят переменные в этой области, если они были замаскированы как локальная переменная любой из функций в их дереве вызовов. Таким образом, нет одной глобальной и одной локальной области видимости.
Здесь полезно знать историю.
В ksh93
, функция, по крайней мере одна объявленная с синтаксисом ksh (function f {...}
), следует за статической областью видимости .
Переменные, объявленные с помощью typeset
в функции, являются локальными переменными функции.
a=global_a
function f {
typeset a=f_a
g
}
function g {
echo "$a"
}
f
выведет global_a
.
typeset -i var
в функции изменяет тип локального var
переменная с созданием ее экземпляра в области видимости функции, если она не было уже.
В ksh93
, функция, объявленная с синтаксисом Борна (f() {...}
), вообще не выполняет область видимости. В связи с этим код функции выглядит так, как будто встроен в вызывающую функцию,поэтому любая переменная, появляющаяся в нем, будет иметь ту же область действия, что и в вызывающем объекте, поэтому либо глобальная, либо локальная для верхней -большей части функции, объявленной с синтаксисом ksh в ее дереве вызовов. typeset
объявил бы переменную в самой верхней -самой функции (или в глобальной области видимости, если в дереве вызовов )не было синтаксической функции ksh -.
Например, поскольку в синтаксических функциях ksh -все переменные являются либо частными, либо глобальными, чтобы реализовать наш integer
как в bash
, нам нужно будет сделать это как:
integer() { typeset -i "$1"; }
То есть используется синтаксис функции Борна , который не выполняет область видимости в все.
Или с использованием синтаксиса ksh:
function integer { typeset -i "$1"; }
, но вызывается как:
. integer var
(, то есть посредством с использованием .
, код целого числа интерпретируется в контекст вызывающего абонента, например, когда вы вызываете.
(source
)на сценарий ).
Или используя синтаксис ksh:
function integer { typeset -ni "$1"; }
Где переменная передается как ссылка с -n
, как в C или большинство других языков программирования.
Все другие Bourne -подобные оболочки (, включая ksh88, ksh93, были полностью переписаны, и изменение статической области видимости было (воспринято как минимум )предварительным -необходимым условием для функциональные возможности, которые когда-либо будут включены в стандарт POSIX)реализуют динамическую область видимости .
Переменная, объявленная с typeset
без -g
в функции, имеет локальную область видимости функции.
Например, typeset -i var
объявит локальную переменную (в текущей области действия функции )и установит целочисленный атрибут .
Например, в коде вверху все они будут выводить f_a
. То есть g
видит локальную переменную f
.
Другой пример:если f
вызывает g
, который вызывает h
. Если h
делает не объявлять var
переменную локальную в своей области видимости, она увидит g
переменная или, возможно, f
, если g
не объявил var
локальным, или, возможно, переменная из нижней -самой области видимости.
Во всех bash
, zsh
, yash
, mksh
, можно изменить тип или значение переменной в функции, не делая ее локальной для этой функции, используяtypeset -g
. Как с этим integer
в приведенном вами примере. Но это делается по-разному в зависимости от оболочки.
В mksh
, yash
, zsh
, typeset -g
не влияет на переменную в нижней -самой(глобальной)области видимости, но в том объеме, в котором он определен в настоящее время .
Например, в то время как typeset -i var
объявляет локальную переменную (в текущей области действия функции )и устанавливает целочисленный атрибут , typeset -gi var
просто делает последнюю часть (без влияющие на сферу примененияvar
).
Например, когда функция вызывает мою функцию integer
выше, чтобы добавить целочисленный атрибут к переменной, как в:
f() {
local myvar
integer myvar
...
}
Он хочет integer
изменить атрибуты своей переменной myvar
, а не той, которая находится в глобальной области видимости, о которой он ничего не знает и, возможно, не сможет получить к ней доступ.
Вbash
typeset -g
влияет на экземпляр переменной в глобальной (нижней -самой )области . Хотя это то, что означает g
, это бесполезно в оболочках с динамическим область видимости, например bash
.
Например, в первом примере в вашем вопрос, вывод 1+1
показывает, что целочисленный атрибут имеет не добавлено в переменную. В добавлена переменная a
в глобальной области видимости, но не той, что функция f
имеет доступ к.
Такой компилятор, как clang++
, компилирует только исходный код. В вашем случае он создает исполняемый файл a.out
(, поскольку вы явно не указали ему использовать другое имя выходного файла, используя параметр -o
). Компилятор не будет автоматически запускать полученный исполняемый файл.Эти вещи также справедливы дляg++
(компилятора GNU C++ ), а также для clang
и gcc
компиляторов C (и большинства других компиляторов языков, требующих компиляции ).
Чтобы запустить исполняемый файл, введите команду
./a.out
в командной строке оболочки.
Чтобы дать исполняемому файлу имя, отличное от традиционного по умолчанию a.out
, используйте что-то вроде
clang++ -o myprog file_name.cpp
для создания myprog
из исходников в file_name.cpp
.
Учитывая исходники в одном файле file_name.cpp
, make
также можно использовать для компиляции исходников в исполняемый файл file_name
с помощью команды
make file_name
находясь в том же каталоге, что и файл исходного кода (, но только если исходный код был обновлен с момента последней компиляции file_name
). Для этого не требуется присутствия Makefile
, вместо этого будут использоваться неявные правила, встроенные в make
для компиляции исходных кодов C++.
Используйте
CXX=clang++ make file_name
для явного использования компилятора clang++
.
Для получения дополнительной информации см. документацию GNU make
о неявных правилах(других реализациях make
, например. в системах BSD используйте аналогичные неявные правила ).