Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет82/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   78   79   80   81   82   83   84   85   ...   256
Байланысты:
Бьерн Страуструп. Язык программирования С . М Бином, 2011

4.2 Связывание 
Если явно не определено иначе, то имя, не являющееся локальным для некоторой функции или класса
должно обозначать один и тот же тип, значение, функцию или объект во всех единицах трансляции 
данной программы. Иными словами, в программе может быть только один нелокальный тип, значение, 
функция или объект с данным именем. Рассмотрим для примера два файла: 
// file1.c 


Бьерн Страуструп.
Язык программирования С++ 
 
98 
int a = 1; 
int f() { /* какие-то операторы */ } 
// file2.c 
extern int a; 
int f(); 
void g() { a = f(); } 
В функции g() используются те самые a и f(), которые определены в файле file1.c. Служебное слово 
extern показывает, что описание a в файле file2.c является только описанием, но не определением. 
Если бы присутствовала инициализация a, то extern просто проигнорировалось бы, поскольку описание 
с инициализацией всегда считается определением. Любой объект в программе может определяться 
только один раз. Описываться же он может неоднократно, но все описания должны быть согласованы 
по типу. Например: 
// file1.c: 
int a = 1; 
int b = 1; 
extern int c; 
// file2.c: 
int a; 
extern double b; 
extern int c; 
Здесь содержится три ошибки: переменная a определена дважды ("int a;" - это определение, 
означающее "int a=0;"); b описано дважды, причем с разными типами; c описано дважды, но 
неопределено. Такие ошибки (ошибки связывания) транслятор, который обрабатывает файлы по 
отдельности, обнаружить не может, но большая их часть обнаруживается редактором связей. 
Следующая программа допустима в С, но не в С++: 
// file1.c: 
int a; 
int f() { return a; } 
// file2.c: 
int a; 
int g() { return f(); } 
Во-первых, ошибкой является вызов f() в file2.c, поскольку в этом файле f() не описана. Во-вторых, 
файлы программы не могут быть правильно связаны, поскольку a определено дважды. 
Если имя описано как static, оно становится локальном в этом файле. Например: 
// file1.c: 
static int a = 6; 
static int f() { /* ... */ } 
// file2.c: 
static int a = 7; 
static int f() { /* ... */ } 
Приведенная программа правильна, поскольку a и f определены как статические. В каждом файле своя 
переменная a и функция f(). 
Если переменные и функции в данной части программы описаны как static, то в этой части программы 
проще разобраться, поскольку не нужно заглядывать в другие части. Описывать функции как 
статические полезно еще и по той причине, что транслятору предоставляется возможность создать 
более простой вариант операции вызова функции. Если имя объекта или функции локально в данном 
файле, то говорят, что объект подлежит внутреннему связыванию. Обратно, если имя объекта или 
функции нелокально в данном файле, то он подлежит внешнему связыванию. 
Обычно говорят, что имена типов, т.е. классов и перечислений, не подлежат связыванию. Имена 


Бьерн Страуструп.
Язык программирования С++ 
 
99 
глобальных классов и перечислений должны быть уникальными во всей программе и иметь 
единственное определение. Поэтому, если есть два даже идентичных определения одного класса, это - 
все равно ошибка: 
// file1.c: 
struct S { int a; char b; }; 
extern void f(S*); 
// file2.c: 
struct S { int a; char b; }; 
void f(S* p) { /* ... */ } 
Но будьте осторожны: опознать идентичность двух описаний класса не в состоянии большинство 
систем программирования С++. Такое дублирование может вызвать довольно тонкие ошибки (ведь 
классы в разных файлах будут считаться различными). 
Глобальные функции-подстановки подлежат внутреннему связыванию, и то же по умолчанию 
справедливо для констант. Синонимы типов, т.е. имена typedef, локальны в своем файле, поэтому 
описания в двух данных ниже файлах не противоречат друг другу: 
// file1.c: 
typedef int T; 
const int a = 7; 
inline T f(int i) { return i+a; } 
// file2.c: 
typedef void T; 
const int a = 8; 
inline T f(double d) { cout<Константа может получить внешнее связывание только с помощью явного описания: 
// file3.c: 
extern const int a; 
const int a = 77; 
// file4.c: 
extern const int a; 
void g() { cout<В этом примере g() напечатает 77. 


Достарыңызбен бөлісу:
1   ...   78   79   80   81   82   83   84   85   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет