Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Глобальные переменные с модификатором static

Цель работы

Цель выполнения данной лабораторной работы состоит в изучении следующих вопросов:

· сборка программ из нескольких файлов с исходным кодом

· формирование заголовочных файлов

· работа с модификаторами классов памяти

Теоретические сведения

Сборка программ из нескольких файлов с исходным кодом

Программа на языке С – это совокупность функций. Запуск любой программы начинается с запуска главной функции (функция main), содержащей в себе всю остальную часть программы. Внутри главной функции для реализации заданного алгоритма вызываются все другие необходимые функции. Часть функций создается самим программистом, другая часть – библиотечные функции – поставляется пользователю со средой программирования и используется в процессе разработки программ (например, printf(), sqrt() и др.).

Простейший метод использования нескольких функций подразумевает их размещения в одном и том же файле. Обычно простые программы состоят из одного исходного файла. Дело обстоит несколько сложнее, если эта программа становится большой. При работе с такой программой может возникнуть несколько достаточно серьезных проблем:

1. Файл, становясь большим, увеличивает время компиляции, и малейшие изменения в исходном тексте автоматически вынуждают тратить время программиста на перекомпиляцию программы.

2. Если над программой работает много человек, то практически невозможно отследить сделанные изменения.

3. Процесс правки и ориентирования при большом исходном тексте становится сложным,поэтому поиск небольшой ошибки может повлечь за собой вынужденное "изучение" кода заново.

Это далеко не все проблемы, которые могут возникнуть при наличии программы "монстра". Поэтому при разработке программ рекомендуется их разбивать на куски, которые функционально ограничены и закончены.

Для того, чтобы вынести функцию или переменную в отдельный файл надо перед ней поставить зарезервированное слово extern. Давайте для примера создадим программу из нескольких файлов. Сначала создадим главную программу, в которой будут две внешние процедуры. Назовем этот файл main.c:


 

#include<stdio.h>

 

// описываем функцию f1() как внешнюю

externint f1();

 

// описываем функцию f2() как внешнюю

externintf2();

 

// описываем переменную а как внешнюю

externinta;

 

int main()

{

int n1, n2;

 

n1 = f1();

n2 = f2();

 

printf("f1() = %d\n",n1);

printf("f2() = %d\n",n2);

printf("a = %d\n",a);

 

return 0;

}

Теперь с помощью меню «проект» добавляем два новых элемента: два с++ файла, каждый из которых будет содержать полное определение внешней функции из главной программы. Файлы назовем f1.c и f2.c:

// файл f1.c

inta;

int f1()

{

return 2;

}

 

// файл f2.c

int f2()

{

return 10;

}

Использование заголовочных файлов

Если бы при использовании любых переменных, функций или типов из других файлов необходимо было бы перечислять их все в своем файле, писать программы было бы весьма неудобно (помните ли вы наизусть типы аргументов и возвращаемых значений всех используемых вами стандартных функций?) – поэтому разработчики библиотек функций выделяют их описания в отдельные файлы с расширением.h (от header–заголовок). Для создания такого файла в среде VisualStudio 2008 в меню «проект» выбираем пункт «добавить новый элемент» и указываем на шаблон «Заголовочный файл(.h)». Например, вместе с файлами f1.cи f2.cпоставлялся бы fileheader.h со следующим содержимым:

int f1();

int f2();

extern int a;

 

В таком случае в main.c достаточно было бы написать #include «fileheader.h». Это намного удобнее явного перечисления необходимых функций и переменных.

В заголовочном файле могут присутствовать только extern – описания переменных, заголовки функций (без реализации), определения структур и typedef – определения типов.

Классы памяти

Классы памяти функций

Функция может быть либо внешней (по умолчанию), либо статической. К внешней функции доступ могут осуществлять функции из других файлов, в то же время статическая функция может использоваться только в файле, в котором она определена. Например, возможны следующие объявления функций:

doublegamma(); // внешняя функция по умолчанию

static double beta();

extern double delta();

 

Функция gamma() и delta() могут использоваться функциями из других файлов, которые являются частью программы, тогда как beta() – нет. В силу этого применение функции beta() ограничено одним файлом, поэтому в других файлах можно использовать функции с тем же именем. Одна из причин использования класса статической памяти заключается в необходимости создания функций, приватных для конкретных модулей, благодаря чему во многих случаях удается избежать конфликта имен.

Обычная практика состоит в том, что при объявлении функции, определенной в другом файле, указывается ключевое слово extern. При этом просто достигается большая ясность, поскольку при объявлении функция и предполагается как extern, если только не задано ключевое слово static.

Классы памяти переменных

Рассмотрим различные классы памяти, соответствующие различным переменным в программе на С.

Класс памяти auto: локальные переменные

Переменные, определенные внутри функций или блоков, называют локальными или автоматическими (поскольку память под них выделяется автоматически). Говорят, что такие переменные соответствуют классу памяти auto (и это можно даже явно указать в коде: два фрагмента ниже эквивалентны).

 


void f(void)

{

int a;

....

}
void f(void)

{

autoint a;

....

}


Если переменной не присвоено значение при определении (как в примере выше), её значение будет не определено (в ней будет содержаться «мусор» из памяти).

Автоматические переменные теряют своё значение при выходе из блока, в котором они были определены.

Локальные переменные с модификатором static

Если локальная переменная (переменная внутри функции) определена с модификатором static(например, staticinta;), то она будет сохранять своё значение между вызовами функции. Инициализация такой переменной сработает только при первом вызове функции, а если переменной не присвоено значение при её определении, её значением будет ноль.

В следующем примере counter считает, сколько раз была вызвана функция f:

void f(void)

{

staticint counter;

counter++;

}

Глобальные переменные

Глобальные переменные определяются вне функций. Они существуют в памяти на протяжении всей работы программы. Если глобальной переменной не присвоено значение при её определении, она будет равна нулю. Чтобы глобальная переменная была «видна» из другого файла (другой единицы компиляции), в другом файле она должна быть объявлена как extern.

Глобальные переменные с модификатором static

Если глобальная переменная (переменная вне функций) определена с модификатором static, она будет доступна только из того файла, в котором она определена. Из других файлов получить доступ к ней не получится даже с использованием extern.

Такие переменные удобно использовать для хранения данных, общих для функций из одного файла, но не предназначенных для использования другими функциями. Например, реализация стека на связном списке (функции push, pop, empty) могут обращаться к первому элементу списка (head), но тем, кто использует стек, эта переменная не нужна, следовательно, её можно определить с модификатором static.

Модификатор static так же можно использовать при определении функций; такие функции тоже будут доступны только из того файла, в котором они были определены.

Регистровые переменные

Указав для локальной переменной модификатор register (например, registerinta;), мы советуем компилятору разместить её в регистре процессора (а не в оперативной памяти), что ускорит обращение к ней. Регистров ограниченное число, и компилятор вправе как прислушаться к нашему совету, так и проигнорировать его. Современные компиляторы обычно принимают решение о размещении переменной в регистре самостоятельно. Тем не менее, независимо от того, размещена ли реально переменная в регистре или нет, к переменной registerнельзя применять оператор взятия адреса &, потому что она может храниться в регистре процессора, который обычно не имеет адреса.Ощутимый эффект от спецификатора register может быть получен только для переменных целого (int) и символьного (char) типа.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...