Доступ к функциям в многомодульной программе
При вызове функции из другого модуля нужно объявить ее как extern и далее описать прототип. В этом случае функция становится видна в другом модуле. Если объявление глобально, то ее можно вызывать в любой функции данного модуля. Если объявление локально, то она доступна только в той функции, где сделано объявление.
Файл 1 Файл 2
Таблица 1. Классы памяти и инициализация
Класс Хранения | Внешний Extern | Внешний Статический static | Аргумен. Функции | Автоматические auto | Регистровые Register | Внурен. Статические Static |
Область действия | Программа | Модуль | Функция | Блок | Блок | Блок |
Время Жизни | Программа | Программа | Функция | Блок | Блок | Программа |
Область Хранения | Сегмент Данных | Сегмент данных | Сегмент стека | Сегмент стека | Регистры МП | Сегмент данных |
Инициал-емость объектов | Все | Все | Не раз-решена в Си | Все в С++ | Все | Все |
Момент инициализации | На стадии Компил. | На стадии компил. | При входе в блок | При входе в блок | При входе в блок | На стадии компил. |
Инициализация по умолчан. | Инициализируются 0 | Инициализируются 0 | Значение указывается | Значение не опред. | Значение не опред. | Инициализируется 0 |
ПРЕПРОЦЕССОР ЯЗЫКА СИ
Компиляция выполняет еще один шаг перед собственно компиляцией исходного файла, называемый предварительно обработкой. Препроцессор просматривает программу и заменяет символьные аббревиатуры в программе на соответствующие директивы. Он расширяет возможности языка 3 функциями.
1. Подстановкой имен;
2. Включением файлов;
3. Условной компиляцией.
Это позволяет создавать мобильные, более удобочитаемые и более удобные для сопровождения программы.
# - первый символ в левой позиции, в любом месте исходного файла сообщает препроцессору, что далее следует директива. Она имеет действие до конца файла.
Подстановка имен
Директивы:
#define– создать макроопределение
#undef- удалить макроопределение
Директива #define служит для:
а) определения символических констант
#define TWO 2
#define MSG “Приднестровский Университет”
#define PX printf(“X равен %d\n”,x)
#define FMT “X равен %d”
void main (void) {
int x=TWO;
PX;
Printf(FMT,x);
Printf(“%s\n”,MSG);
Printf(“TWO:MSG\n”);
}
Макроопределение не должно содержать пробелы. Процесс прохождения от макроопределения до заключительной строки называется макрорасширением. Препроцессор делает подстановки.
б) Макроопределение с аргументом
Очень похоже на функцию (макро-функция).
#define SQUARE(x) x*x
#define PR(x) printf(“X равен %d\n”,x)
void main(void) {
int x=4; int z;
z=SQUARE(x); //16
PR(z);
Z=SQUARE(2); //4
PR(z);
PR(SQUARE(X));
PR(100/SQUARE(2));//100
PR(SQUARE(X+2)); //14
PR(SQUARE(++X)); //30
}
Макрофункция ведет к увеличению программы. Функция к увеличению времени работы программы. Макроопределение создает строчный код, не нужно заботится о типах переменных.
Включение файлов
Директива #include позволяет включить в текст содержимое файла, имя которого является параметром директивы.
1. #include <stdio.h> - ищет в системном каталоге
2. #include “stdio.h” – ищет в текущем рабочем каталоге.
3. Можно создавать свои файлы с функциями и подключать.
#include “my_file.cpp”
4. Можно подключать макроопределение. Макрорасширение макроса должно приводить к одной из первых двух форм директивы.
#define MY_FILE “d:\\bc\work\\my_file.h”
#include MY_FILE
Условная компиляция
Позволяет компилировать не все части программы. Директивы условной компиляции исползуются в больших программах.
#if константное_выражение
[фрагмент текста]
[#elif константное_выражение
фрагмент текста]
...
[#else фрагмент текста]
#endif
Результатом вычисления константного_выражения является целое число. Если оно не 0, то выполняется фрагмент текста программы от директивы #if до одной из директив #else, #elif или #endif.
1. #ifdef CI
#include <stdio.h>
#define MAX 80
#else
#include <iostream.h>
#define MAX 132
#endif
2. #ifndef – если макроопределение не определено
#ifndef MY_FILE // файл будет компилироваться только один раз
#define MY_FILE //когда макрос не определен
#include “my_fyle”
#endif
3. #if SYS == ”IBM”
//похоже на оператор, за ним следует константное выражение
//которое считается истинным, если оно не равно 0
#endif
4. Можно исключить блок программы
#ifdef любое имя
*****
#endif
#if defined(__LARGE__)||defined(__HUGE__)
typedef INT long
#else
typedef INT int
#endif
УКАЗАТЕЛИ
Память состоит из байтов, каждый из которых пронумерован, начиная с 0, 1, 2 ... Номер – это адрес. В Си есть переменные, которые могут содержать этот адрес – указатели и операция взятия адреса - &.
int var=1; - определение и инициализация переменной. var – её имя.
printf ("%d %d\n",var, &var); 1 12136
Машинный код команды можно выразить словами. "Выделить 2 байта памяти, присвоить им имя var. Поместить в ячейку с адресом 12136 число". Фактический адрес этой переменной 12136, а его символическое представление &var.
Значением переменной типа указатель служит адрес некоторой величины. Дадим имя этой переменной ptr; тогда можно написать ptr=&var;
В этом случае говорим "ptr указывает на var", где ptr-переменная, &var-константа.
ptr=# - теперь указывает на num.
13.1 Операция косвенной адресации *
Для доступа к переменной, адрес которой помещен в ptr, используется операция косвенной адресации.
val=*ptr; //val==num
*ptr = 10; //num==10
Описание указателей
Мы уже знаем как описываются переменные, массивы. Как же описать указатель! Сложность в том, что переменные разных типов содержат разное число ячеек, но операции с указателями требуют знания отведенной им памяти. Поэтому, при определении указателя, мы описываем, на какой тип переменной она будет указывать, и что это указатель символ *.
int* ptr;
float* pmas;
char* pc;