Обычная СИ-программа представляет собой определение функции main, которая для выполнения необходимых действий вызывает другие функции. Приведенные выше примеры программ представляли собой один исходный файл, содержащий все необходимые для выполнения программы функции. Связь между функциями осуществлялась по данным посредством передачи параметров и возврата значений функций. Но компилятор языка СИ позволяет также разбить программу на несколько отдельных частей (исходных файлов), оттранслировать каждую часть отдельно, и затем объединить все части в один выполняемый файл при помощи редактора связей.
main () < . >fun1()
fun2() < . >fun3()
Для того, чтобы определяемая функция могла выполнять какие либо действия, она должна использовать переменные. В языке СИ все переменные должны быть объявлены до их использования. Объявления устанавливают соответствие имени и атрибутов переменной, функции или типа. Определение переменной вызывает выделение памяти для хранения ее значения. Класс выделяемой памяти определяется спецификатором класса памяти, и определяет время жизни и область видимости переменной, связанные с понятием блока программы.
Язык программирования Си. Урок 1. Базовая структура программы
В языке СИ блоком считается последовательность объявлений, определений и операторов, заключенная в фигурные скобки. Существуют два вида блоков — составной оператор и определение функции, состоящее из составного оператора, являющегося телом функции, и предшествующего телу заголовка функции (в который входят имя функции, типы возвращаемого значения и формальных параметров). Блоки могут включать в себя составные операторы, но не определения функций. Внутренний блок называется вложенным, а внешний блок — объемлющим.
Время жизни — это интервал времени выполнения программы, в течение которого программный объект (переменная или функция) существует. Время жизни переменной может быть локальным или глобальным. Переменная с глобальным временем жизни имеет распределенную для нее память и определенное значение на протяжении всего времени выполнения программы, начиная с момента выполнения объявления этой переменной. Переменная с локальным временем жизни имеет распределенную для него память и определенное значение только во время выполнения блока, в котором эта переменная определена или объявлена. При каждом входе в блок для локальной переменной распределяется новая память, которая освобождается при выходе из блока.
Все функции в СИ имеют глобальное время жизни и существуют в течение всего времени выполнения программы.
Область видимости — это часть текста программы, в которой может быть использован данный объект. Объект считается видимым в блоке или в исходном файле, если в этом блоке или файле известны имя и тип объекта. Объект может быть видимым в пределах блока, исходного файла или во всех исходных файлах, образующих программу. Это зависит от того, на каком уровне объявлен объект: на внутреннем, т.е. внутри некоторого блока, или на внешнем, т.е. вне всех блоков.
Если объект объявлен внутри блока, то он видим в этом блоке, и во всех внутренних блоках. Если объект объявлен на внешнем уровне, то он видим от точки его объявления до конца данного исходного файла.
2. Структура программы на языке С++
Объект может быть сделан глобально видимым с помощью соответствующих объявлений во всех исходных файлах, образующих программу.
Спецификатор класса памяти в объявлении переменной может быть auto, register, static или extern. Если класс памяти не указан, то он определяется по умолчанию из контекста объявления.
Объекты классов auto и register имеют локальное время жизни. Спецификаторы static и extern определяют объекты с глобальным временем жизни.
При объявлении переменной на внутреннем уровне может быть использован любой из четырех спецификаторов класса памяти, а если он не указан, то подразумевается класс памяти auto.
Переменная с классом памяти auto имеет локальное время жизни и видна только в блоке, в котором объявлена. Память для такой переменной выделяется при входе в блок и освобождается при выходе из блока. При повторном входе в блок этой переменной может быть выделен другой участок памяти.
Переменная с классом памяти auto автоматически не инициализируется. Она должна быть проинициализирована явно при объявлении путем присвоения ей начального значения. Значение неинициализированной переменной с классом памяти auto считается неопределенным.
Спецификатор класса памяти register предписывает компилятору распределить память для переменной в регистре, если это представляется возможным. Использование регистровой памяти обычно приводит к сокращению времени доступа к переменной. Переменная, объявленная с классом памяти register, имеет ту же область видимости, что и переменная auto. Число регистров, которые можно использовать для значений переменных, ограничено возможностями компьютера, и в том случае, если компилятор не имеет в распоряжении свободных регистров, то переменной выделяется память как для класса auto. Класс памяти register может быть указан только для переменных с типом int или указателей с размером, равным размеру int.
Переменные, объявленные на внутреннем уровне со спецификатором класса памяти static, обеспечиваю возможность сохранить значение переменной при выходе из блока и использовать его при повторном входе в блок. Такая переменная имеет глобальное время жизни и область видимости внутри блока, в котором она объявлена. В отличие от переменных с классом auto, память для которых выделяется в стеке, для переменных с классом static память выделяется в сегменте данных, и поэтому их значение сохраняется при выходе из блока.
Пример: /* объявления переменной i на внутреннем уровне с классом памяти static. */ /* исходный файл file1.c */ main() < . >fun1() < static int i=0; . >/* исходный файл file2.c */ fun2() < static int i=0; . >fun3()
В приведенном примере объявлены три разные переменные с классом памяти static, имеющие одинаковые имена i. Каждая из этих переменных имеет глобальное время жизни, но видима только в том блоке (функции), в которой она объявлена. Эти переменные можно использовать для подсчета числа обращений к каждой из трех функций.
Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то такой переменной присваивается нулевое значение. При инициализации константным адресным выражением можно использовать адреса любых внешних объектов, кроме адресов объектов с классом памяти auto, так как адрес последних не является константой и изменяется при каждом входе в блок. Инициализация выполняется один раз при первом входе в блок.
Переменная, объявленная локально с классом памяти extern, является ссылкой на переменную с тем же самым именем, определенную глобально в одном из исходных файлов программы. Цель такого объявления состоит в том, чтобы сделать определение переменной глобального уровня видимым внутри блока.
Пример: /* объявления переменной i, являющейся именем внешнего массива длинных целых чисел, на локальном уровне */ /* исходный файл file1.c */ main() < . >fun1() < extern long i[]; . >/* исходный файл file2.c */ long i[MAX]=; fun2() < . >fun3()
Объявление переменной i[] как extern в приведенном примере делает ее видимой внутри функции fun1. Определение этой переменной находится в файле file2.c на глобальном уровне и должно быть только одно, в то время как объявлений с классом памяти extern может быть несколько.
Объявление с классом памяти extern требуется при необходимости использовать переменную, описанную в текущем исходном файле, но ниже по тексту программы, т.е. до выполнения ее глобального определения. Следующий пример иллюстрирует такое использование переменной с именем st.
Пример: main() < extern int st[]; . >static int st[MAX]=; fun1()
Объявление переменной со спецификатором extern информирует компилятор о том, что память для переменной выделять не требуется, так как это выполнено где-то в другом месте программы.
При объявлении переменных на глобальном уровне может быть использован спецификатор класса памяти static или extern, а так же можно объявлять переменные без указания класса памяти. Классы памяти auto и register для глобального объявления недопустимы.
Объявление переменных на глобальном уровне — это или определение переменных, или ссылки на определения, сделанные в другом месте программы. Объявление глобальной переменной, которое инициализирует эту переменную (явно или неявно), является определением переменной. Определение на глобальном уровне может задаваться в следующих формах:
1. Переменная объявлена с классом памяти static. Такая переменная может быть инициализирована явно константным выражением, или по умолчанию нулевым значением. То есть обявления static int i=0 и static int i эквивалентны, и в обоих случаях переменной i будет присвоено значение 0.
2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.
Переменная объявленная глобально видима в пределах остатка исходного файла, в котором она определена. Выше своего описания и в других исходных файлах эта переменная невидима (если только она не объявлена с классом extern).
Глобальная переменная может быть определена только один раз в пределах своей области видимости. В другом исходном файле может быть объявлена другая глобальная переменная с таким же именем и с классом памяти static, конфликта при этом не возникает, так как каждая из этих переменных будет видимой только в своем исходном файле.
Спецификатор класса памяти extern для глобальных переменных используется, как и для локального объявления, в качестве ссылки на переменную, объявленную в другом месте программы, т.е. для расширения области видимости переменной. При таком объявлении область видимости переменной расширяется до конца исходного файла, в котором сделано объявление.
В объявлениях с классом памяти extern не допускается инициализация, так как эти объявления ссылаются на уже существующие и определенные ранее переменные.
Переменная, на которую делается ссылка с помощью спецификатора extern, может быть определена только один раз в одном из исходных файлов программы.
1.6.2. Объявления функций
Функции всегда определяются глобально. Они могут быть объявлены с классом памяти static или extern. Объявления функций на локальном и глобальном уровнях имеют одинаковый смысл.
Правила определения области видимости для функций отличаются от правил видимости для переменных и состоят в следующем.
1. Функция, объявленная как static, видима в пределах того файла, в котором она определена. Каждая функция может вызвать другую функцию с классом памяти static из своего исходного файла, но не может вызвать функцию определенную с классом static в другом исходном файле. Разные функции с классом памяти static имеющие одинаковые имена могут быть определены в разных исходных файлах, и это не ведет к конфликту.
2. Функция, объявленная с классом памяти extern, видима в пределах всех исходных файлов программы. Любая функция может вызывать функции с классом памяти extern.
3. Если в объявлении функции отсутствует спецификатор класса памяти, то по умолчанию принимается класс extern.
Все объекты с классом памяти extern компилятор помещает в объектном файле в специальную таблицу внешних ссылок, которая используется редактором связей для разрешения внешних ссылок. Часть внешних ссылок порождается компилятором при обращениях к библиотечным функциям СИ, поэтому для разрешения этих ссылок редактору связей должны быть доступны соответствующие библиотеки функций.
1.6.3. Время жизни и область видимости программных объектов
Время жизни переменной (глобальной или локальной) определяется по следующим правилам.
1. Переменная, объявленная глобально (т.е. вне всех блоков), существует на протяжении всего времени выполнения программы.
2. Локальные переменные (т.е. объявленные внутри блока) с классом памяти register или auto, имеют время жизни только на период выполнения того блока, в котором они объявлены. Если локальная переменная объявлена с классом памяти static или extern, то она имеет время жизни на период выполнения всей программы.
Видимость переменных и функций в программе определяется следующими правилами.
1. Переменная, объявленная или определенная глобально, видима от точки объявления или определения до конца исходного файла. Можно сделать переменную видимой и в других исходных файлах, для чего в этих файлах следует ее объявить с классом памяти extern.
2. Переменная, объявленная или определенная локально, видима от точки объявления или определения до конца текущего блока. Такая переменная называется локальной.
3. Переменные из объемлющих блоков, включая переменные объявленные на глобальном уровне, видимы во внутренних блоках. Эту видимость называют вложенной. Если переменная, объявленная внутри блока, имеет то же имя, что и переменная, объявленная в объемлющем блоке, то это разные переменные, и переменная из объемлющего блока во внутреннем блоке будет невидимой.
4. Функции с классом памяти static видимы только в исходном файле, в котором они определены. Всякие другие функции видимы во всей программе.
Метки в функциях видимы на протяжении всей функции.
Имена формальных параметров, объявленные в списке параметров прототипа функции, видимы только от точки объявления параметра до конца объявления функции.
1.6.4. Инициализация глобальных и локальных переменных
При инициализации необходимо придерживаться следующих правил:
1. Объявления содержащие спецификатор класса памяти extern не могут содержать инициаторов.
2. Глобальные переменные всегда инициализируются, и если это не сделано явно, то они инициализируются нулевым значением.
3. Переменная с классом памяти static может быть инициализирована константным выражением. Инициализация для них выполняется один раз перед началом программы. Если явная инициализация отсутствует, то переменная инициализируется нулевым значением.
4. Инициализация переменных с классом памяти auto или register выполняется всякий раз при входе в блок, в котором они объявлены. Если инициализация переменных в объявлении отсутствует, то их начальное значение не определено.
5. Начальными значениями для глобальных переменных и для переменных с классом памяти static должны быть константные выражения. Адреса таких переменных являются константами и эти константы можно использовать для инициализации объявленных глобально указателей. Адреса переменных с классом памяти auto или register не являются константами и их нельзя использовать в инициаторах.
Пример: int global_var; int func(void) < int local_var; /* по умолчанию auto */ static int *local_ptr= /* так неправильно */ static int *global_ptr= /* а так правильно */ register int *reg_ptr= /* и так правильно */ >
В приведенном примере глобальная переменная global_var имеет глобальное время жизни и постоянный адрес в памяти, и этот адрес можно использовать для инициализации статического указателя global_ptr. Локальная переменная local_var, имеющая класс памяти auto размещается в памяти только на время работы функции func, адрес этой переменной не является константой и не может быть использован для инициализации статической переменной local_ptr. Для инициализации локальной регистровой переменной reg_ptr можно использовать неконстантные выражения, и, в частности, адрес переменной local_ptr. [ Назад | Оглавление | Вперед ]
- 23.06 — Платежи с помощью NFC станут быстрее и по-настоящему бесконтактными
- 23.06 — «Роскосмос» показал «царь-двигатель» РД-171МВ для перспективных ракет «Союз-5»
- 23.06 — Precision Neuroscience впервые подключила свой нейроинтерфейс к мозгу человека — раньше, чем Neuralink
- 23.06 — Бруклинский комплекс Bathhouse использует майнинг-серверы для подогрева воды
- 21.06 — Доступен дистрибутив SUSE Linux Enterprise 15 SP5
- 21.06 — Учёные «заморозили» свет в объёме материала, но пока только на компьютерной модели
- 21.06 — Starlink объявила о запуске работы спутников второго поколения, но есть нюансы
- 21.06 — Доступные маршрутизаторы с Wi-Fi 7 выйдут через полгода — Broadcom представила соответствующие платформы
- 21.06 — Европейским компаниям запретят производить критически важные чипы в Китае
- 21.06 — Microsoft избавит «Проводник» в Windows 11 от устаревших настроек — отобразить системные файлы станет сложнее
- 21.06 — «Почта» и «Календарь» исчезнут из Windows 11 — их заменители появятся в новом Outlook
- 21.06 — Опубликован Wolvic 1.4, web-браузер для устройств виртуальной реальности
- 20.06 — В App Store появился российский браузер «Луна» с сертификатами безопасности Минцифры
- 20.06 — Защищённая операционная система KasperskyOS появится в смартфонах, причём не только в России
- 20.06 — NVIDIA находится в шаге от того, чтобы стать крупнейшим разработчиком чипов
- 20.06 — Нейросеть YandexGPT стала доступна сторонним разработчикам
- 20.06 — Apple намерена зарегистрировать изображение реального яблока как торговую марку — это может навредить фермерам и не только
- 20.06 — WhatsApp стал заглушать звонки с неизвестных номеров
- 20.06 — На Солнце произошли две сильные вспышки — это вызвало перебои радиосвязи на Земле
- 20.06 — Все, кто пользовался поиском Google в 2006–2013 годах, могут получить денежную компенсацию
Источник: citforum.ru
1 язык си структура программы на языке си
Обычная СИ-программа представляет собой определение функции main, которая для выполнения необходимых действий вызывает другие функции. Приведенные выше примеры программ представляли собой один исходный файл, содержащий все необходимые для выполнения программы функции. Связь между функциями осуществлялась по данным посредством передачи параметров и возврата значений функций. Но компилятор языка СИ позволяет также разбить программу на несколько отдельных частей (исходных файлов), оттранслировать каждую часть отдельно, и затем объединить все части в один выполняемый файл при помощи редактора связей.
main () < . >fun1()
fun2() < . >fun3()
Для того, чтобы определяемая функция могла выполнять какие либо действия, она должна использовать переменные. В языке СИ все переменные должны быть объявлены до их использования. Объявления устанавливают соответствие имени и атрибутов переменной, функции или типа. Определение переменной вызывает выделение памяти для хранения ее значения. Класс выделяемой памяти определяется спецификатором класса памяти, и определяет время жизни и область видимости переменной, связанные с понятием блока программы.
В языке СИ блоком считается последовательность объявлений, определений и операторов, заключенная в фигурные скобки. Существуют два вида блоков — составной оператор и определение функции, состоящее из составного оператора, являющегося телом функции, и предшествующего телу заголовка функции (в который входят имя функции, типы возвращаемого значения и формальных параметров). Блоки могут включать в себя составные операторы, но не определения функций. Внутренний блок называется вложенным, а внешний блок — объемлющим.
Время жизни — это интервал времени выполнения программы, в течение которого программный объект (переменная или функция) существует. Время жизни переменной может быть локальным или глобальным. Переменная с глобальным временем жизни имеет распределенную для нее память и определенное значение на протяжении всего времени выполнения программы, начиная с момента выполнения объявления этой переменной. Переменная с локальным временем жизни имеет распределенную для него память и определенное значение только во время выполнения блока, в котором эта переменная определена или объявлена. При каждом входе в блок для локальной переменной распределяется новая память, которая освобождается при выходе из блока.
Все функции в СИ имеют глобальное время жизни и существуют в течение всего времени выполнения программы.
Область видимости — это часть текста программы, в которой может быть использован данный объект. Объект считается видимым в блоке или в исходном файле, если в этом блоке или файле известны имя и тип объекта. Объект может быть видимым в пределах блока, исходного файла или во всех исходных файлах, образующих программу. Это зависит от того, на каком уровне объявлен объект: на внутреннем, т.е. внутри некоторого блока, или на внешнем, т.е. вне всех блоков.
Если объект объявлен внутри блока, то он видим в этом блоке, и во всех внутренних блоках. Если объект объявлен на внешнем уровне, то он видим от точки его объявления до конца данного исходного файла.
Объект может быть сделан глобально видимым с помощью соответствующих объявлений во всех исходных файлах, образующих программу.
Спецификатор класса памяти в объявлении переменной может быть auto, register, static или extern. Если класс памяти не указан, то он определяется по умолчанию из контекста объявления.
Объекты классов auto и register имеют локальное время жизни. Спецификаторы static и extern определяют объекты с глобальным временем жизни.
При объявлении переменной на внутреннем уровне может быть использован любой из четырех спецификаторов класса памяти, а если он не указан, то подразумевается класс памяти auto.
Переменная с классом памяти auto имеет локальное время жизни и видна только в блоке, в котором объявлена. Память для такой переменной выделяется при входе в блок и освобождается при выходе из блока. При повторном входе в блок этой переменной может быть выделен другой участок памяти.
Переменная с классом памяти auto автоматически не инициализируется. Она должна быть проинициализирована явно при объявлении путем присвоения ей начального значения. Значение неинициализированной переменной с классом памяти auto считается неопределенным.
Спецификатор класса памяти register предписывает компилятору распределить память для переменной в регистре, если это представляется возможным. Использование регистровой памяти обычно приводит к сокращению времени доступа к переменной. Переменная, объявленная с классом памяти register, имеет ту же область видимости, что и переменная auto. Число регистров, которые можно использовать для значений переменных, ограничено возможностями компьютера, и в том случае, если компилятор не имеет в распоряжении свободных регистров, то переменной выделяется память как для класса auto. Класс памяти register может быть указан только для переменных с типом int или указателей с размером, равным размеру int.
Переменные, объявленные на внутреннем уровне со спецификатором класса памяти static, обеспечиваю возможность сохранить значение переменной при выходе из блока и использовать его при повторном входе в блок. Такая переменная имеет глобальное время жизни и область видимости внутри блока, в котором она объявлена. В отличие от переменных с классом auto, память для которых выделяется в стеке, для переменных с классом static память выделяется в сегменте данных, и поэтому их значение сохраняется при выходе из блока.
Пример: /* объявления переменной i на внутреннем уровне с классом памяти static. */ /* исходный файл file1.c */ main() < . >fun1() < static int i=0; . >/* исходный файл file2.c */ fun2() < static int i=0; . >fun3()
В приведенном примере объявлены три разные переменные с классом памяти static, имеющие одинаковые имена i. Каждая из этих переменных имеет глобальное время жизни, но видима только в том блоке (функции), в которой она объявлена. Эти переменные можно использовать для подсчета числа обращений к каждой из трех функций.
Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то такой переменной присваивается нулевое значение. При инициализации константным адресным выражением можно использовать адреса любых внешних объектов, кроме адресов объектов с классом памяти auto, так как адрес последних не является константой и изменяется при каждом входе в блок. Инициализация выполняется один раз при первом входе в блок.
Переменная, объявленная локально с классом памяти extern, является ссылкой на переменную с тем же самым именем, определенную глобально в одном из исходных файлов программы. Цель такого объявления состоит в том, чтобы сделать определение переменной глобального уровня видимым внутри блока.
Пример: /* объявления переменной i, являющейся именем внешнего массива длинных целых чисел, на локальном уровне */ /* исходный файл file1.c */ main() < . >fun1() < extern long i[]; . >/* исходный файл file2.c */ long i[MAX]=; fun2() < . >fun3()
Объявление переменной i[] как extern в приведенном примере делает ее видимой внутри функции fun1. Определение этой переменной находится в файле file2.c на глобальном уровне и должно быть только одно, в то время как объявлений с классом памяти extern может быть несколько.
Объявление с классом памяти extern требуется при необходимости использовать переменную, описанную в текущем исходном файле, но ниже по тексту программы, т.е. до выполнения ее глобального определения. Следующий пример иллюстрирует такое использование переменной с именем st.
Пример: main() < extern int st[]; . >static int st[MAX]=; fun1()
Объявление переменной со спецификатором extern информирует компилятор о том, что память для переменной выделять не требуется, так как это выполнено где-то в другом месте программы.
При объявлении переменных на глобальном уровне может быть использован спецификатор класса памяти static или extern, а так же можно объявлять переменные без указания класса памяти. Классы памяти auto и register для глобального объявления недопустимы.
Объявление переменных на глобальном уровне — это или определение переменных, или ссылки на определения, сделанные в другом месте программы. Объявление глобальной переменной, которое инициализирует эту переменную (явно или неявно), является определением переменной. Определение на глобальном уровне может задаваться в следующих формах:
1. Переменная объявлена с классом памяти static. Такая переменная может быть инициализирована явно константным выражением, или по умолчанию нулевым значением. То есть обявления static int i=0 и static int i эквивалентны, и в обоих случаях переменной i будет присвоено значение 0.
2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.
Переменная объявленная глобально видима в пределах остатка исходного файла, в котором она определена. Выше своего описания и в других исходных файлах эта переменная невидима (если только она не объявлена с классом extern).
Глобальная переменная может быть определена только один раз в пределах своей области видимости. В другом исходном файле может быть объявлена другая глобальная переменная с таким же именем и с классом памяти static, конфликта при этом не возникает, так как каждая из этих переменных будет видимой только в своем исходном файле.
Спецификатор класса памяти extern для глобальных переменных используется, как и для локального объявления, в качестве ссылки на переменную, объявленную в другом месте программы, т.е. для расширения области видимости переменной. При таком объявлении область видимости переменной расширяется до конца исходного файла, в котором сделано объявление.
В объявлениях с классом памяти extern не допускается инициализация, так как эти объявления ссылаются на уже существующие и определенные ранее переменные.
Переменная, на которую делается ссылка с помощью спецификатора extern, может быть определена только один раз в одном из исходных файлов программы.
1.6.2. Объявления функций
Функции всегда определяются глобально. Они могут быть объявлены с классом памяти static или extern. Объявления функций на локальном и глобальном уровнях имеют одинаковый смысл.
Правила определения области видимости для функций отличаются от правил видимости для переменных и состоят в следующем.
1. Функция, объявленная как static, видима в пределах того файла, в котором она определена. Каждая функция может вызвать другую функцию с классом памяти static из своего исходного файла, но не может вызвать функцию определенную с классом static в другом исходном файле. Разные функции с классом памяти static имеющие одинаковые имена могут быть определены в разных исходных файлах, и это не ведет к конфликту.
2. Функция, объявленная с классом памяти extern, видима в пределах всех исходных файлов программы. Любая функция может вызывать функции с классом памяти extern.
3. Если в объявлении функции отсутствует спецификатор класса памяти, то по умолчанию принимается класс extern.
Все объекты с классом памяти extern компилятор помещает в объектном файле в специальную таблицу внешних ссылок, которая используется редактором связей для разрешения внешних ссылок. Часть внешних ссылок порождается компилятором при обращениях к библиотечным функциям СИ, поэтому для разрешения этих ссылок редактору связей должны быть доступны соответствующие библиотеки функций.
1.6.3. Время жизни и область видимости программных объектов
Время жизни переменной (глобальной или локальной) определяется по следующим правилам.
1. Переменная, объявленная глобально (т.е. вне всех блоков), существует на протяжении всего времени выполнения программы.
2. Локальные переменные (т.е. объявленные внутри блока) с классом памяти register или auto, имеют время жизни только на период выполнения того блока, в котором они объявлены. Если локальная переменная объявлена с классом памяти static или extern, то она имеет время жизни на период выполнения всей программы.
Видимость переменных и функций в программе определяется следующими правилами.
1. Переменная, объявленная или определенная глобально, видима от точки объявления или определения до конца исходного файла. Можно сделать переменную видимой и в других исходных файлах, для чего в этих файлах следует ее объявить с классом памяти extern.
2. Переменная, объявленная или определенная локально, видима от точки объявления или определения до конца текущего блока. Такая переменная называется локальной.
3. Переменные из объемлющих блоков, включая переменные объявленные на глобальном уровне, видимы во внутренних блоках. Эту видимость называют вложенной. Если переменная, объявленная внутри блока, имеет то же имя, что и переменная, объявленная в объемлющем блоке, то это разные переменные, и переменная из объемлющего блока во внутреннем блоке будет невидимой.
4. Функции с классом памяти static видимы только в исходном файле, в котором они определены. Всякие другие функции видимы во всей программе.
Метки в функциях видимы на протяжении всей функции.
Имена формальных параметров, объявленные в списке параметров прототипа функции, видимы только от точки объявления параметра до конца объявления функции.
1.6.4. Инициализация глобальных и локальных переменных
При инициализации необходимо придерживаться следующих правил:
1. Объявления содержащие спецификатор класса памяти extern не могут содержать инициаторов.
2. Глобальные переменные всегда инициализируются, и если это не сделано явно, то они инициализируются нулевым значением.
3. Переменная с классом памяти static может быть инициализирована константным выражением. Инициализация для них выполняется один раз перед началом программы. Если явная инициализация отсутствует, то переменная инициализируется нулевым значением.
4. Инициализация переменных с классом памяти auto или register выполняется всякий раз при входе в блок, в котором они объявлены. Если инициализация переменных в объявлении отсутствует, то их начальное значение не определено.
5. Начальными значениями для глобальных переменных и для переменных с классом памяти static должны быть константные выражения. Адреса таких переменных являются константами и эти константы можно использовать для инициализации объявленных глобально указателей. Адреса переменных с классом памяти auto или register не являются константами и их нельзя использовать в инициаторах.
Пример: int global_var; int func(void) < int local_var; /* по умолчанию auto */ static int *local_ptr= /* так неправильно */ static int *global_ptr= /* а так правильно */ register int *reg_ptr= /* и так правильно */ >
Источник: www.helloworld.ru
Общая структура программы на языке Си Всякая программа на языке Си представляет собой совокупность одной или более функций, каждая из которых есть независимый. — презентация
Презентация на тему: » Общая структура программы на языке Си Всякая программа на языке Си представляет собой совокупность одной или более функций, каждая из которых есть независимый.» — Транскрипт:
1 Общая структура программы на языке Си Всякая программа на языке Си представляет собой совокупность одной или более функций, каждая из которых есть независимый набор описаний и операторов, заключенных между заголовком функции и ее концом Та функция, с которой начинается выполнение программы, называется главной функцией. Она по существу является входной точкой программы и должна иметь предопределенное имя main() Все остальные функции, возможно входящие в состав программы и выполняющие конкретную часть работы по реализации алгоритма решения задачи, играют подчиненную роль и запускаются в работу путем их прямого или опосредованного (через другие функции) вызова из главной функции
2 Работа всей программы обычно заканчивается по достижении конца главной функции, однако ее выполнение может быть прекращено путем передачи управления операционной системе из произвольной точки программы Любая функция, в том числе и главная, может иметь один или более формальных параметров, которые используются для передачи в ее тело необходимых числовых значений в момент вызова Наличие параметров у главной функции является специфической особенностью языка Си и используется для обработки аргументов командной строки при обращении к программе
3 Несмотря на то, что функции в языке Си представляют собой основные строительные блоки всякой программы, при рассмотрении примеров и задач предыдущих лекций нам уже приходилось встречаться с определением переменных, констант и литерных цепочек вне какой бы то ни было функции, или, иначе говоря, на внешнем уровне Именно так мы поступали при работе с включаемыми файлами, содержащими определения системных констант и предварительные описания функций, или желая сделать какую-либо переменную доступной сразу нескольким функциям Определенные на внешнем уровне объекты уже теряют свойство локальности по отношению к функциям и формируют программную оболочку, называемую глобальной средой
4 Для дальнейшего изучения структуры Си-программы, нам необходимо определить понятия времени существования и видимости различных объектов, участвующих в ее работе Под временем существования переменной или функции обычно понимают продолжительность их реального нахождения в памяти компьютера Те объекты программы, которые создаются в момент начала ее работы и существуют вплоть до полного завершения последней, принято называть объектами с глобальным временем существования Переменные и структуры данных, создающиеся динамически в процессе работы программы и ликвидируемые раньше ее фактического завершения, будем называть объектами с локальным временем существования
5 Память под представление локальных объектов выделяется компилятором в момент входа в ту программную компоненту, которая содержит описания этих объектов, и возвращается назад операционной системе по достижении ее конца Под видимостью переменной или функции следует понимать ту область исходной программы, в пределах которой разрешена работа с этой переменной или обращение к соответствующей функции Объекты программы, обращение к которым разрешено из любой ее точки, называют объектами с глобальной видимостью Таковыми, например, являются все функции, входящие в состав программы, а также переменные и структуры данных, определенные вне какой-либо функции
6 Те переменные, область доступа к которым ограничена некоторой частью исходной программы, мы будем называть переменными с локальной видимостью Так, локальную видимость имеют любые объекты, описанные в теле функции, если только не принято специальных мер для расширения области доступа к ним Общее правило, определяющее время существования и видимость объектов программы, основывается на фундаментальном понятии блока Под блоком в языке Си понимается совокупность описаний и операторов, заключенных в фигурные скобки
7 Это понятие является прямым обобщением введенного понятия составного оператора Принципиальное их отличие состоит в том, что состав блока наряду с исполняемыми операторами входят описания переменных или структур данных Согласно семантическим правилам языка, всякий элемент данных, определенный внутри блока, имеет локальную видимость и время существования в пре делах этого блока Иными словами, элемент данных создается в момент входа в блок и ликвидируется при выходе из него, причем доступ к этому элементу ограничен рамками текущего блока
8 Тело всякой функции в смысле новой терминологии представляет собой правильный блок со всеми вытекающими отсюда ограничениями на время существования и видимость внутренних переменных данной функции Об описаниях объектов программы в каком-либо блоке мы будем говорить как об определяющих этот объект на внутреннем уровне Описания констант, переменных, структур данных или функций вне всякого блока будем называть внешними описаниями или описаниями на внешнем уровне
9 Мы уже говорили о том, что описание переменных в Си-программах допустимо как на внешнем, так и на внутреннем уровнях, причем время существования и видимость внутренних переменных ограничена текущим блоком В случае же внешнего описания, переменная имеет глобальное время существования, а ее видимость ограничена частью программы от той точки, где встретилось это описание, до конца текущего файла В отличие от описаний переменных, определения функций могут размещаться лишь на внешнем уровне, и поэтому всякая функция имеет глобальное время существования и глобальную видимость по отношению к программе в целом Никакая функция не может содержать внутри себя определение другой функции с локальной видимостью
10 В то же время, внутри любого блока допустимо предварительное описание функций, используемых в этом блоке, что, однако, не сужает области видимости таких функций Правильные блоки в программе на языке Си могут быть вложены один в другой, порождая тем самым нелокальную среду ссылок При этом внутренний блок может содержать описания переменных с теми же именами, что и во внешнем блоке Это ведет к локальному переопределению соответствующих переменных во внутреннем блоке. Прежние значения этих переменных восстанавливаются после передачи управления какому- либо оператору внешнего блока
11 В следующем фрагменте программы, выполняющем суммирование элементов двух целочисленных массивов, идентификатор sum во внутреннем и внешнем блоках обозначает различные объекты, каждый из которых имеет свое собственное размещение в памяти компьютера: void summa(int *tab_1, int m, int *tab_2, int n) < int i, sum; sum = 0; for (i = 0; i
12 Аналогичная ситуация возникает и в том случае, когда какая-либо переменная, определенная внутри блока, имеет то же самое имя, что и некоторая внешняя переменная. Здесь, так же как и ранее, локальное описание замещает внешнее описание переменной, восстанавливая ее прежнее значение по завершении работы блока Исходный текст Си-программы допускается подразделять на несколько файлов, каждый из которых содержит необходимые описания переменных и определения функций Компиляция всех таких файлов должна производиться раздельно с последующей сборкой соответствующих объектных модулей на этапе построения готовой к выполнению программы Ниже, будут сформулированы условия, при которых разрешены ссылки на объекты за пределами текущего файла
13 В качестве примера программы, содержащей как внешние, так и внутренние описания, приведем реализацию алгоритма сортировки числового массива по возрастанию элементов методом перестановки:
15 В этом примере массив вещественных чисел mas определен на внешнем уровне и поэтому доступен обеим функциям программы Переменные mind и buf определены локально во внутреннем блоке функции main() и область их видимости ограничена одним этим блоком То же самое имя mind использовано в теле функции maxind() для обозначения текущего значения индекса максимального элемента и никоим образом не связано с его определением функции main() Аналогичное замечание можно сделать и относительно параметра цикла i в главной и вспомогательной функциях
16 Классы памяти Понятие классов памяти дает возможность определить, с какими функциями связаны какие переменные и как долго тот или иной объект программы сохраняется в памяти компьютера Назначая класс памяти для какого-либо элемента, программист определяет тем самым время существования этого элемента (глобальное или локальное) Область же видимости элемента данных характеризуется уровнем (внешним или внутренним), на котором он определен в программе
17 Существуют четыре основных класса памяти: auto extern static register называемые описателями класса памяти Описателями класса памяти обычно появляются в инструкциях описания данных перед именем типа, модифицируя семантику соответствующего описания. Они оказывают влияние не только на время существования, но и на область видимости того или иного объекта программы Значения описателей класса памяти будут различными в зависимости от уровня программы (внешнего или внутреннего), на котором они встречаются, а также от того, применены ли они при описании переменной или функции Ниже рассмотрены четыре возможных случая назначения класса памяти для различных объектов программы
18 Автоматические переменные (класс памяти auto) Объекты программы, принадлежащие классу памяти auto и именуемые обычно автоматическими переменными, имеют локальное время существования и область их видимости ограничена тем блоком, в котором они определены Память для их представления выделяется динамически из программного стека в момент входа в этот блок и возвращается назад системе по достижении его конца
19 По умолчанию все переменные, описанные на внутреннем уровне (т. е. в теле функции), являются автоматическими. Однако это можно явно подчеркнуть, используя ключевое слово auto : void main() < auto int alpha, beta; auto char line[81];. >Поскольку любые переменные, описанные на внешнем уровне, должны иметь глобальное время существования и размещаются поэтому в статической памяти, использование описателя auto вне какого-либо блока является недопустимым и приводит к ошибке
20 По этой же причине не разрешается назначать класс памяти auto для функций, ибо их определения не могут быть помещены в тело программного блока Инициализация простых автоматических переменных задается обычным образом и выполняется при каждом входе в соответствующий блок В случае же отсутствия инициализирующего выражения в инструкции описания данных, значение любой такой переменной считается неопределенным Инициализация любых агрегатированных данных (например, массивов), имеющих класс памяти auto, не поддерживается компилятором языка Си
21 Замечание Поскольку память под представление автоматических переменных выделяется из программного стека, при построении готовой к выполнению программы из объектных модулей необходимо задать размер стека таким, чтобы его хватило для размещения всех этих переменных в самой большой по объему данных программной компоненте
22 Внешние объекты программы (класс памяти extern ) Внешними объектами программы принято называть переменные, определенные вне какой-либо функции, и сами эти функции, поскольку определение одной функции в теле другой не является допустимым По умолчанию всякая внешняя переменная имеет глобальное время существования, а область ее видимости лежит между точкой описания в программе и концом текущего файла Это означает, что любая функция, определенная после описания некоторой внешней переменной в пределах одного файла, может использовать эту переменную без каких-либо дополнительных объявлений
23 Если же возникает необходимость в использовании внешних переменных до их фактического определения в текущем или даже другом файле, их нужно явным образом описать как имеющие класс памяти extern в теле соответствующей функции В следующем примере: void main() < extern int number;. >. int number = 17;. переменная number используется функцией main() раньше, чем она определена в программе Ее начальное значение в этой функции равно 17
24 С точки зрения рассмотренных понятий времени существования и видимости объектов программы, важно различать описания внешних переменных и их определения Так, описания начинаются с ключевого слова extern и могут встречаться многократно на внешнем и внутреннем уровнях, задавая тем самым область видимости соответствующих переменных Отсутствие описателя extern при определении внешней переменной требует от системы фактического выделения памяти для ее размещения. Любая такая переменная может быть определена лишь один раз во всей совокупности файлов, образующих исходную программу Инициализация внешних переменных и структур данных всегда допустима в инструкциях, определяющих эти объекты в программе, и выполняется один раз перед началом ее работы
25 Те элементы данных, для которых инициализирующие выражения явным образом не заданы, по умолчанию инициализируются нулем Инструкции описания внешних переменных, начинающиеся с ключевого слова extern, не могут содержать инициализирующих выражений Использование внешний переменных в программах на языке Си часто оказывается полезным в тех случаях, когда возникает необходимость в передаче больших объемов информации между отдельными функциями или когда множество функций используют одни и те же данные Однако неоправданное расширение области видимости большого количества переменных путем их обобществления может снизить надежность программного обеспечения.
26 Статические переменные и функции (класс памяти static ) Описатель класса памяти static может использоваться в инструкциях определения данных как на внешнем, так и на внутреннем уровнях Внешние статические переменные имеют глобальное время существования, однако в отличие от обычных внешних переменных, доступ к ним ограничен частью текущего файла, лежащей после определения любой такой переменной в программе Ссылка на статические переменные из другого файла или их использование до фактического определения в текущем файле не допустимо Таким образом, описатель static позволяет сузить область видимости внешней переменной
27 Внутренние статические переменные, как и переменные класса auto, имеют локальную видимость в пределах текущей функции (или блока), однако они сохраняются в памяти компьютера на протяжении всего времени работы программы Это позволяет создавать объекты с глобальным временем существования, ограничивая их видимость в программе Так, например, переменная count, определенная в теле функции calc : void main() <. >void calc() < static int count;. >может быть использована только в пределах этой функции, хотя она и сохраняет свое значение после завершения работы последней
28 Класс памяти static можно также назначать и при определении функций, ограничивая тем самым возможность доступа к ним пределами одного файла Это позволяет иметь в разных файлах функции с одинаковыми именами, не опасаясь возникновения конфликтной ситуации Инициализация статических переменных и структур данных допустима как на внешнем, так и на внутреннем уровнях, и выполняется по тем же правилам, что и для обычных внешних переменных
29 Регистровые переменные (класс памяти register) Регистровые переменные с точки зрения видимости, времени существования и возможностей инициализации полностью равносильны автоматическим переменным Однако они сохраняются не в оперативной памяти машины, а на рабочих регистрах центрального процессора, что повышает эффективность выполнения программы Если возможность такого хранения отсутствует (скажем, по причине занятости этих регистров), они становятся обычными автоматическими переменными Этот класс памяти может назначаться только лишь для внутренних переменных и формальных параметров функций при помощи описателя register
30 Например: void func(p, q) register int p, q; < register char sym;. >Операция получения адреса для регистровых переменных не допустима На многих типах компьютеров этот класс памяти не может быть назначен переменным типа float
31 Классы имен В программах на языке Си идентификаторы используются для именования большого числа различных объектов, таких как константы, переменные, функции, теги и элементы структур, метки и т. д. С целью облегчения выбора имен и снижения вероятности возникновения конфликтных ситуаций, компилятор языка подразделяет все множество идентификаторов на несколько взаимно не пересекающихся классов В пределах одного и того же класса всякое имя должно быть уникальным с учетом области видимости и времени существования связанного с этим именем объекта программы
32 С другой стороны, одинаковые имена могут обозначать множество объектов, принадлежащих различным классам, не приводя при этом к противоречию на этапах компиляции, сборки и выполнения программы. Ниже приводится описание классов памяти, поддерживаемых компилятором. 1. Наиболее крупный и важный класс составляют имена переменных, функций, формальных параметров, перечисляемых констант и типов данных, определенных с помощью инструкции typedef. Идентификаторы, обозначающие соответствующие объекты, не должны совпадать между собой на одном и том же уровне программы 2. Другой существенный класс образуют теги структур, объединений и перечислений, имена которых должны быть различными в пределах одного уровня видимости. Однако допускается совпадение имен тегов с именами переменных, функций, элементов структур и прочих объектов из смежных классов
33 3. В отдельный класс выделяются имена элементов индивидуальных структур и объединений. Это означает, что они должны быть уникальными в пределах каждой конкретной структуры или объединения, однако могут совпадать с именами, принадлежащими другим классам или различным структурам и объединениям 4. Последний и самый малочисленный класс образуют имена меток инструкций программы. Они не должны совпадать между собой в пределах одной программной компоненты (функции), однако не обязаны отличаться от имен, принадлежащих другим классам или определенных в различных программных единицах
Источник: www.myshared.ru