|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Классы памятиКласс памяти переменной, которая определяет какой либо об"ект, имеет глобальное или локальное время жизни. Об"ект с глобальным временем жизни существует и имеет значение на протяжении всей программы. Все функции имеют глобальное время жизни. Переменные с локальным временем жизни захватывают новую па- мять при каждом выполнении блока, в котором они определены. Когда управление на выполнение передается из блока, то переменная теря- ет свое значение. Хотя Си определяет два типа классов памяти, но, тем не менее, имеется следующих четыре спецификатора классов памяти: auto register static extern Об"екты классов auto и register имеют локальное время жизни. Спецификаторы static и extern определяют об"екты с глобальным временем жизни. Каждый из спецификаторов класса памяти имеет определенный смысл, который влияет на видимость функций и переменных в той же мере, как и сами классы памяти. Термин "видимость" относится к той части программы, в которой могут ссылаться друг на друга функции и переменные. Об"екты с глобальным временем жизни существуют на протяжении выполнения исходной программы, но они могут быть видимы не во всех частях программы. Видимость и связанная с ней концепция времени жизни рассмотрена в разделе 3.5. Месторасположение об"явления переменной или функции внутри исходных файлов также влияют на класс памяти и видимость. Говорят, что об"явления вне определения всех функций и переменных относятся к внешнему уровню, а об"явления внутри определений функций относятся к внутреннему уровню. Точный смысл каждого спецификатора класса памяти зависит от того, находится ли об"явление на внешнем или внутреннем уровне и от того, об"явлен ли об"ект функцией или переменной. В следующем разделе описывается смысл спецификаторов класса памяти в каждом случае об"явления, а также об"ясняется режим умолчания, когда спецификатор класса памяти опущен при об"явлении переменной или функции. Об"явления переменной на внешнем уровне Об"явления переменной на внешнем уровне используют спецификаторы класса памяти static и extern или совсем опускают их. Спецификаторы класса памяти auto и register не допускаются на внешнем уровне. Об"явления переменных на внешнем уровне- это определения переменных или ссылки на определения, сделанные в другом месте. Об"явление внешней переменной, которое инициализирует эту переменную (явно или неявно), называется определением этой переменной. Определение на внешнем уровне может задаваться в следующих различных формах: -переменная на внешнем уровне может быть определена путем ее об"явления со спецификатором класса памяти static. Такая переменная может быть явно инициализирована константным выражением. Если инициализатор отсутствует, то переменная автоматически инициализируется нулем во время компиляции. Таким образом, об"явления static int k = 16; и static int k; оба рассматриваются как определения; -переменная определяется, когда она явно инициализируется на внешнем уровне. Например, int j = 3; это определение переменной. Так как переменная определяется на внешнем уровне, то она видима в пределах остатка исходного файла, от места, где она определена. Переменная не видима выше своего определения в том же самом исходном файле ни в других исходных файлах программы, если не об"явлена ссылка, которая делает ее видимой. Переменная может быть определена на внешнем уровне внутри исходного файла только один раз. Если задается спецификатор класса памяти static, то в других исходных файлах могут быть определены переменные с тем же именем. Так как каждое определение static видимо только в пределах своего собственного исходного файла, то конфликта не возникнет. Спецификатор класса памяти extern используется для об"явления ссылки на переменную, определенную где-то в другом месте. Такие об"явления используются в случае, когда нужно сделать видимым определение переменной в других исходных файлах или выше места, где она определена в том же самом исходном файле. Так как ссылка на переменную об"явлена на внешнем уровне, то переменная видима в пределах остатка исходного файла от места об"явления ссылки. В об"явлениях, которые используют спецификатор класса памяти extern, инициализация не допускается, так как они ссылаются на переменные, чьи величины уже определены. Переменная, на которую делается ссылка extern, должна быть определена на внешнем уровне только один раз. Определение может быть сделано в любом из исходных файлов, составляющих программу. Есть одно исключение из правил, описанных выше. Можно опус- тить из об"явления переменной на внешнем уровне спецификатор класса памяти и инициализатор. Например, об"явление int n; будет правильным внешним об"явлением. Это об"явление имеет два различных смысла в зависимости от контекста. 1. Если где-нибудь в программе будет определена на внешнем уровне переменная с тем же именем, то об"явление является ссылкой на эту переменную, как если бы был использован спецификатор класса памяти extern в об"явлении. 2. Если нет такого определения, то об"явленной переменной распределяется память во время линкования и переменная инициализируется нулем. Если в программе появится более чем одно такое об"явление, то память распределится для наибольшего размера из об"явленных переменных. Например, если программа содержит два неинициализированных об"явления переменной i на внешнем уровне int i; и char i; то память во время линкования распределится под переменную i типа int. Неинициализированные об"явления переменной на внешнем уровне не рекомендуются для файлов, которые могут быть размещены в библиотеку. Пример: /***************************************************** SOURCE FILE ONE *****************************************************/ extern int i; /* reference to i defined below */ main() { i++; printf("%d\n", i); /* i equals 4 */ next(); } int i = 3; /* definition of i */ next() { i++; printf("%d\n", i); /* i equals 5 */ other(); } /***************************************************** SOURCE FILE TWO *****************************************************/ extern int i; /* reference to i in first source file */ other() { i++; printf("%d\n", i); /* i equals 6 */ } Два исходных файла в совокупности содержат три внешних об"явления i. Одно об"явление содержит инициализацию- int i = 3;, где глобальная переменная i определена с начальным значением равным 3. Самое первое об"явление extern в первом файле делает глобальную переменную видимой выше ее определения в файле. Без об"явления extern функция main не смогла бы сослаться на глобальную переменную i. Об"явление extern переменной i во втором исходном файле делает глобальную переменную видимой в этом исходном файле. Все три функции выполняют одну и ту же задачу: они увеличивают i на 1 и печатают получившееся значение. (Предполагается, что функция printf определена где-то еще в программе.). Печатаются величины равные 4, 5 и 6. Если бы переменная i не была бы инициализирована,она бы была автоматически установлена в 0 при линковании. В этом случае напечатанные значения были бы равны 1, 2 и 3. Об"явление переменной на внутреннем уровне Любой из четырех спецификаторов класса памяти может быть использован для об"явления переменной на внутреннем уровне. Если спецификатор класса памяти опускается в об"явлении переменной на внутреннем уровне, то подразумевается класс памяти auto. Спецификатор класса памяти auto об"являет переменную с ло- кальным временем жизни. Переменная видима только в том блоке, где она об"явлена. Об"явления переменных auto могут включать инициализаторы. Переменные класса памяти auto автоматически не инициализируются, а инициализируются явно при об"явлении или присваивании начальных значений, посредством операторов внутри блока. Если нет инициализации, то величина переменной auto считается неопределенной. Спецификатор класса памяти register сообщает компилятору о том, чтобы он распределил память под переменную в регистре, если это возможно. Использование регистровой памяти обычно приводит к более быстрому времени доступа и к меньшему размеру результирующего кода. Переменные, об"явленные с классом памяти register име- ют ту же самую видимость, что и переменные auto. Число регистров, которое может быть использовано под память переменных, зависит от машины. Когда компилятор встречает спецификатор класса памяти register в об"явлении, а свободного регистра не имеется, то для переменной распределяется память класса auto. Компилятор назначает переменным регистровую память в том порядке, в котором появляются об"явления в исходном файле. Регистровая память, если она имеется, гарантирована только для целого и адресного типов. Переменная, об"явленная на внутреннем уровне со спецификатором класса памяти static,имеет глобальное время жизни и имеет видимость только внутри блока, в котором она об"явлена. В отличие от переменных auto, переменные, об"явленные как static, сохраняют свое значение при завершении блока. Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то переменная класса памяти static автоматически устанавливается в 0. Инициализация выполняется один раз во время компиляции. Инициализация переменной класса памяти static не повторяется при новом входе в блок. Переменная, об"явленная со спецификатором класса памяти extern, является ссылкой на переменную с тем же самым именем, определенную на внешнем уровне в любом исходном файле программы. Цель внутреннего об"явления extern состоит в том, чтобы сделать определение переменной внешнего уровня видимой внутри блока. Внутреннее об'явление extern не изменяет видимость глобальной переменной в любой другой части программы. Пример: int i = 1; main() { /* reference to i, defined above */ extern int i; /* initial value is zero; a is visible only within main */ static int a; /* b is stored in a register, if possible */ register int b = 0; /* default storage class is auto */ int c = 0; /* values printed are 1, 0, 0, 0 */ printf("%d\n%d\n%d\n%d\n", i, a, b, c); other(); } other() { /* i is redefined */ int i = 16; /* this a is visible only within other */ static int a = 2; a += 2; /* values printed are 16, 4 */ printf("%d\n%d\n", i, a); } Переменная i определяется на внешнем уровне с инициализацией 1. В функции main об"явлена ссылка extern на переменную i внешнего уровня. Переменная класса памяти static автоматически устанавливается в 0, так как инициализатор опущен. Вызов функции print (предполагается, что функция print определена в каком-то месте исходной программы.) печатает величины 1, 0, 0, 0. В функции other, переменная i переопределяется как локальная переменная с начальным значением 16. Это не влияет на значение внешней переменной i. Переменная a об"является как переменная класса памяти static с начальным значением 2. Она не противоречит переменной a, об"явленной в функции main, так как видимость переменных класса памяти static на внутреннем уровне ограничена блоком, в котором она об"явлена. Значение переменной увеличивается на 2 и становится равным 4. Если бы функция other была вызвана снова в той же самой программе, то начальное значение a стало бы равным 4. Внутренние переменные класса памяти static сохраняют свои значения, когда заканчивается выполнение блока, в котором они об"явлены. Об"явление функции на внешнем и внутреннем уровнях Функции могут быть об"явлены со спецификаторами класса памяти static или extern. Функции всегда имеют глобальное время жизни. Правила видимости для функций отличаются от правил видимости для переменных. Об"явления функций на внутреннем уровне имеют тот же самый смысл, что и об"явления на внешнем уровне. Это значит, что функции не могут иметь блочной видимости и видимость функций не может быть вложенной. Функция об"явленная как static, видима только в пределах исходного файла, в котором она определяется. Любая функция в том же самом исходном файле может вызвать функцию static, но функции static из других файлов нет. Функция static с тем же самым именем может быть об"явлена в другом исходном файле. Функции, об"явленные как extern видимы в пределах всех исходных файлов, которые составляют программу. Любая функция может вызвать функцию extern. Об"явления функций, в которых опущен спецификатор класса памяти, считаются по умолчанию extern. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.008 сек.) |