Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
Значение неинициализированной переменной неопределенно. Попытка использования значения неинициализированной переменной является ошибкой, которую зачастую трудно обнаружить. Кроме того, компилятор не обязан обнаруживать такие ошибки, хотя большинство из них предупреждает, по крайней мере, о некоторых случаях использования неинициализированных переменных.
Что же произойдет при использовании неинициализированной переменной с неопределенным значением? Иногда (если повезет) программа отказывает сразу, при попытке доступа к объекту. Обнаружив место, где происходит отказ, как правило, довольно просто выяснить, что его причиной является неправильно инициализированная переменная. Но иногда программа срабатывает, хотя результат получается ошибочным. Возможен даже худший вариант, когда на одной машине результаты получаются правильными, а на другой происходит сбой. Кроме того, добавление кода во вполне работоспособную программу в неподходящем месте тоже может привести к внезапному возникновению проблем.
Мы рекомендуем инициализировать каждый объект встроенного типа. Это не всегда необходимо, но проще и безопасней предоставить инициализатор, чем выяснять, можно ли в данном конкретном случае безопасно опустить его.
Для поддержки раздельной компиляции язык С++ различает объявления и определения. Объявление (declaration) делает имя известным программе. Файл, который должен использовать имя, определенное в другом месте, включает объявление для этого имени. Определение (definition) создает соответствующую сущность.
Объявление переменной определяет ее тип и имя. Определение переменной — это ее объявление. Кроме задания имени и типа, определение резервирует также место для ее хранения и может снабдить переменную исходным значением.
Чтобы получить объявление, не являющееся также определением, добавляется ключевое слово extern и можно не предоставлять явный инициализатор.
extern int i; // объявить, но не определить переменную i
int j; // объявить и определить переменную j
Любое объявление, которое включает явный инициализатор, является определением. Для переменной, определенной как extern (внешняя), можно предоставить инициализатор, но это отменит ее определение как extern. Объявление внешней переменной с инициализатором является ее определением:
extern double pi = 3.1416; // определение
Предоставление инициализатора внешней переменной в функции является ошибкой.
Объявлены переменные могут быть много раз, но определены только однажды.
На настоящий момент различие между объявлением и определением может показаться неочевидным, но фактически оно очень важно. Использование переменной в нескольких файлах требует объявлений, отдельных от определения. Чтобы использовать ту же переменную в нескольких файлах, ее следует определить в одном, и только одном файле. В других файлах, где используется та же переменная, ее следует объявить, но не определять.
Более подробная информация о том, как язык С++ поддерживает раздельную компиляцию, приведена в разделах 2.6.3 и 6.1.3.
Упражнения раздела 2.2.2Упражнение 2.11. Объясните, приведены ли ниже объявления или определения.
(a) extern int ix = 1024;
(b) int iy;
(c) extern int iz;
Ключевая концепция. Статическая типизацияЯзык С++ обладает строгим статическим контролем типов (statically typed) данных. Это значит, что проверка соответствия значений заявленным для них типам данных осуществляется во время компиляции. Сам процесс проверки называют контролем соответствия типов (type-checking), или типизацией (typing).
Как уже упоминалось, тип ограничивает операции, которые можно выполнять с объектом. В языке С++ компилятор проверяет, поддерживает ли используемый тип операции, которые с ним выполняют. Если обнаруживается попытка сделать нечто, не поддерживаемое данным типом, компилятор выдает сообщение об ошибке и не создает исполняемый файл.
По мере усложнения рассматриваемых программ будет со всей очевидностью продемонстрировано, что строгий контроль соответствия типов способен помочь при поиске ошибок в исходном коде. Однако последствием статической проверки является то, что тип каждой используемой сущности должен быть известен компилятору. Следовательно, тип переменной необходимо объявить прежде, чем эту переменную можно будет использовать.
2.2.3. Идентификаторы
Идентификаторы (identifier) (или имена) в языке С++ могут состоять из символов, цифр и символов подчеркивания. Язык не налагает ограничений на длину имен. Идентификаторы должны начинаться с букв или символа подчеркивания. Символы в верхнем и нижнем регистрах различаются, т.е. идентификаторы языка С++ чувствительны к регистру.
// определено четыре разных переменных типа int
int somename, someName, SomeName, SOMENAME;
Язык резервирует набор имен, перечисленных в табл. 2.3 и 2.4, для собственных нужд. Эти имена не могут использоваться как идентификаторы.
Таблица 2.3. Ключевые слова языка С++
alignas continue friend register true alignof decltype goto reinterpret_cast try asm default if return typedef auto delete inline short typeid bool do int signed typename break double long sizeof union case dynamic_cast mutable static unsigned catch else namespace static_assert using char enum new static_cast virtual char16_t explicit noexcept struct void char32_t export nullptr switch volatile class extern operator template wchar_t const false private this while constexpr float protected thread_local const_cast for public throwТаблица 2.4. Альтернативные имена операторов языка С++
and bitand compl not_eq or_eq xor_eq and_eq bitor not or xorКроме ключевых слов, стандарт резервирует также набор идентификаторов для использования в библиотеке, поэтому пользовательские идентификаторы не могут содержать два последовательных символа подчеркивания, а также начинаться с символа подчеркивания, непосредственно за которым следует прописная буква. Кроме того, идентификаторы, определенные вне функций, не могут начинаться с символа подчеркивания.