Доступ к функциям в многомодульной программе

 

При вызове функции из другого модуля нужно объявить ее как 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; - теперь указывает на num.

 

13.1 Операция косвенной адресации *

 

Для доступа к переменной, адрес которой помещен в ptr, используется операция косвенной адресации.

val=*ptr; //val==num

*ptr = 10; //num==10

 

Описание указателей

Мы уже знаем как описываются переменные, массивы. Как же описать указатель! Сложность в том, что переменные разных типов содержат разное число ячеек, но операции с указателями требуют знания отведенной им памяти. Поэтому, при определении указателя, мы описываем, на какой тип переменной она будет указывать, и что это указатель символ *.

 

int* ptr;

float* pmas;

char* pc;