Чем определение отличается от объявления
Перейти к содержимому

Чем определение отличается от объявления

  • автор:

Функции

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

Формальное определение функции выглядит следующим образом:

тип имя_функции(параметры)

Первая строка представляет заголовок функции. Вначале указывается возвращаемый тип функции. Если функция не возвращает никакого значения, то используется тип void .

Затем идет имя функции, которое представляет произвольный идентификатор. К именованию функции применяются те же правила, что и к именованию переменных.

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

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

Для возвращения результата функция применяет оператор return . Если функция имеет в качестве возвращаемого типа любой тип, кроме void, то она должна обязательно с помощью оператора return возвращать какое-либо значение.

Например, определение функции main, которая должна быть в любой программе на языке C++ и с которой начинается ее выполнение:

int main()

Возвращаемым типом функции является тип int , поэтому функция должна использовать оператор return и возвращать какое-либо значение, которое соответствует типу int. Возвращаемое значение ставится после оператора return.

Стоит отметить, что С++ позволяет не использовать оператор return в функции main:

int main()

Но если функция имеет тип void , то ей не надо ничего возвращать. Например, мы могли бы определить следующую функцию, которая просто выводит некоторый текст на консоль:

void hello()

Выполнение функции

Когда запускается программа на языке C++, то запускается функция main. Никакие другие функции, определенные в программе, автоматически не выполняются. Для выполнения функции ее необходимо вызвать. Вызов функции осуществляется в форме:

имя_функции(аргументы);

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

Например, определим и выполним простейшую функцию:

#include void hello() < std::cout int main()

Здесь определена функция hello, которая вызывается в функции main два раза. В этом и заключается преимущество функций: мы можем вынести некоторые общие действия в отдельную функцию и затем вызывать многократно в различных местах программы. В итоге программа два раза выведет строку «hello».

hello hello

Объявление функции

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

#include int main() < hello(); hello(); >void hello()

В этом случае перед вызовом функции надо ее дополнительно объявить. Объявление функции еще называют прототипом. Формальное объявление выглядит следующим образом:

тип имя_функции(параметры);

Фактически это заголовок функции. То есть для функции hello объявление будет выглядеть следующим образом:

void hello();

Используем объявление функции:

#include void hello(); int main() < hello(); hello(); >void hello()

В данном случае несмотря на то, что определение функции идет после ее вызова, но так как функция уже объявлена до ее вызова, то компилятор будет знать о функции hello, и никаких проблем в работе программы не возникнет.

Разница между объявлением и определением в C и C++

В C и C++ есть маленькое, но важное различие между значением слов “объявление” и “определение”. Если вы не понимаете разницы, иногда вы будете получать странные ошибки, такие как:

undefined symbol foo
undefined reference to foo
undefined reference to vtable for foo(в C++)

Что означает “объявление” в C и C++

При объявлении переменной, функции или даже класса все, что вы делаете, это говорите компилятору, что есть что-то с определенным именем и определенного типа. Компилятор может обрабатывать большинство (но не все) использований этого имени, без необходимости полного определения этого имени. Объявление значения, не определяя его, позволяет писать код, понятный компилятору, опуская дополнительные детали. Это особенно полезно, если вы работаете с несколькими исходными файлами и должны использовать функцию в нескольких файлах. Вам не нужно писать тело функции в каждом из файлов, но вы должны объявить ее.

Итак, как же выглядит объявление?

Например, если вы пишете:

int func();

Это объявление функции, оно не включает тело функции, но оно сообщает компилятору, что он может использовать эту функцию, и ожидать, что она будет определена где-то позже.

Что это значит, определить что-то в C и C++ ?

Определение чего-то означает предоставление всей необходимой информации для создания этого целиком. Определение функции означает предоставление тела функции, определение класса означает предоставление всех методов и полей класса. Как только что-то определено, оно также считается объявленным, так что вы можете как объявлять, так и определять функции, классы или переменные одновременно. Но вам это не нужно.

Например, для компилятора часто достаточно объявления. Вы можете написать такой код:

int func(); int main() < int x = func(); >int func()

Так как компилятор знает возвращаемое значение функции, и количество аргументов, которые она принимает, он может скомпилировать вызов функции, даже если она еще не определена. В самом деле, определение функции может быть в другом файле!

Вы также можете объявить класс не определяя его:

class MyClass;

Код, которому нужно знать детали того, что находится в MyClass не будет работать — вы не можете этого сделать:

class MyClass; MyClass an_object; class MyClass < int _a_field; >;

Потому что компилятор должен знать размер переменной an_object, и он не может узнать его из объявления MyClass; ему нужно определение, которое появляется ниже.

Объявление и определение переменных с Extern

В большинстве случаев, когда вы объявляете переменную, вы также определяете ее. Так что же такое определение переменной? Это означает, что вы говорите компилятору, где выделить место для этой переменной. Например, если вы пишете:

int x; int main()

Строка int х , как объявляет так и определяет переменную, она говорит: «создать переменную с именем х , типа int . Кроме того, место хранения переменной определяется тем, что это глобальная переменная, определенная в объектный файл, связанный с этим исходным файлом. Это немного странно, не правда ли? Что произойдет, если кто-то другой напишет второй исходный файл, который имеет такой код:

extern int x; int func()

Использование extern позволяет объявить переменную, не определяя ее, он сообщает, что переменная находится где-то в другом месте. Технически, можно даже написать такой код:

extern int x; int func() < x = 3; >int x;

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

В самом деле, если вы поставите переменную в заголовке файла и не будете использовать extern , вы столкнетесь с обратной задачей неопределенного символа, у вас будет символ с несколькими определениями, с ошибкой типа:

redefinition of ‘foo

Это произойдет, когда компоновщик будет связывать объектные файлы.

Разница между объявлением и определением: Вывод

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

Общие случаи

Если вы хотите использовать функцию в нескольких исходных файлах, вы должны объявить функцию в одном заголовочном файле (.h), а затем определить функцию в одном исходном файле (.c или .cpp). Весь код, который использует функцию должен включать в себя только .h файл, и вам надо связать полученные объектные файлы с объектным файлом от компиляции исходного файла.

Если вы хотите использовать класс в нескольких файлах, вы должны поместить определение класса в заголовочный файл и определить методы класса в соответствующем исходном файле. (Вы также можете использовать встроенные функции для методов).

Если вы хотите использовать переменную в нескольких файлах, вы должны объявить переменную с помощью ключевого слова extern в одном заголовочном файле, а затем включить этот заголовочный файл во все исходные файлы, которым нужна эта переменная. Затем вы должны определить эту переменную в одном исходном файле, который связан со всеми объектными файлами, которые используют эту переменную.

Объявления и определения (C++)

Программа C++ состоит из различных сущностей, таких как переменные, функции, типы и пространства имен. Перед их использованием необходимо объявить каждую из этих сущностей. Объявление указывает уникальное имя сущности, а также сведения о его типе и других характеристиках. В C++ точка объявления имени — это точка, в которой она становится видимой компилятору. Вы не можете ссылаться на функцию или класс, объявленный в какой-то момент в единице компиляции. Переменные должны объявляться как можно ближе до точки, в которой они используются.

В следующем примере показаны некоторые объявления:

#include int f(int i); // forward declaration int main() < const double pi = 3.14; //OK int i = f(2); //OK. f is forward-declared C obj; // error! C not yet declared. std::string str; // OK std::string is declared in header j = 0; // error! No type specified. auto k = 0; // OK. type inferred as int by compiler. > int f(int i) < return i + 42; >namespace N < class C; > 

В строке 5 main функция объявляется. В строке 7 const переменная с именем pi объявлена и инициализирована . В строке 8 целое число i объявляется и инициализируется со значением, созданным функцией f . Имя f видно компилятору из-за объявления пересылки в строке 3.

В строке 9 объявлена переменная типа obj C . Однако это объявление вызывает ошибку, так как C не объявляется до конца программы и не объявляется перенаправленным. Чтобы устранить ошибку, можно переместить все определение C до main или добавить для него объявление вперед. Это поведение отличается от других языков, таких как C#. На этих языках функции и классы можно использовать до их точки объявления в исходном файле.

В строке 10 объявлена переменная типа str std::string . Имя std::string видно, так как оно представлено в string файле заголовка, который объединяется в исходный файл в строке 1. std — это пространство имен, в котором string объявлен класс.

В строке 11 возникает ошибка, так как имя j не было объявлено. Объявление должно предоставлять тип, в отличие от других языков, таких как JavaScript. В строке 12 auto используется ключевое слово, которая сообщает компилятору определить тип k на основе значения, с которым оно инициализировано. Компилятор в этом случае выбирает int тип.

Область видимости объявления

Имя, введенное объявлением, допустимо в область, где происходит объявление. В предыдущем примере переменные, объявленные внутри main функции, являются локальными переменными. Можно объявить другую переменную, именуемую i за пределами основной, в глобальной область, и она будет отдельной сущностью. Однако такое дублирование имен может привести к путанице и ошибкам программиста, и их следует избежать. В строке 21 класс C объявляется в область пространства N имен. Использование пространств имен помогает избежать конфликтов имен. Большинство имен стандартной std библиотеки C++ объявляются в пространстве имен. Дополнительные сведения о взаимодействии правил область с объявлениями см. в разделе «Область».

Определения

Некоторые сущности, включая функции, классы, перечисления и постоянные переменные, должны быть определены, а также объявлены. Определение предоставляет компилятору все сведения, необходимые для создания машинного кода при последующем использовании сущности в программе. В предыдущем примере строка 3 содержит объявление для функции f , но определение функции предоставляется в строках 15–18. В строке 21 класс объявлен и определен (хотя как определено, класс C ничего не делает). Константная переменная должна быть определена, другими словами, присвоено значение в той же инструкции, в которой она объявлена. Объявление встроенного типа, например автоматическое определение, так как int компилятор знает, сколько пространства для него выделяется.

В следующем примере показаны объявления, которые также являются определениями:

// Declare and define int variables i and j. int i; int j = 10; // Declare enumeration suits. enum suits < Spades = 1, Clubs, Hearts, Diamonds >; // Declare class CheckBox. class CheckBox : public Control < public: Boolean IsChecked(); virtual int ChangeState() = 0; >; 

Ниже приведены некоторые объявления, которые не являются определениями:

extern int i; char *strchr( const char *Str, const char Target ); 

Операторы Typedefs и using

В более ранних версиях C++ typedef ключевое слово используется для объявления нового имени, которое является псевдонимом другого имени. Например, тип std::string — это другое имя. std::basic_string Очевидно, почему программисты используют имя typedef, а не фактическое имя. В современном C++ using ключевое слово предпочтительнее typedef , но идея аналогична: новое имя объявляется для сущности, которая уже объявлена и определена.

Статические члены класса

Элементы данных статического класса являются дискретными переменными, общими для всех объектов класса. Так как они совместно используются, они должны быть определены и инициализированы вне определения класса. Дополнительные сведения см. в разделе «Классы».

объявления экстернов

Программа C++ может содержать несколько единиц компиляции. Чтобы объявить сущность, определенную в отдельном модуле компиляции, используйте extern ключевое слово. Сведения в объявлении достаточно для компилятора. Однако если определение сущности не удается найти на шаге связывания, компоновщик вызовет ошибку.

Разница между объявлением и определением в c и C++ Текст научной статьи по специальности «Компьютерные и информационные науки»

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Гагарин Вячеслав Юрьевич

В данной статье рассматривается различие между « определением » и « объявлением » класса , переменной или функции в языках С/С++; рассказывается о том, как избежать возникновения нестандартных ошибок из-за неправильного « определения » или « объявления » класса , переменной или функции .

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Гагарин Вячеслав Юрьевич

Динамически загружаемые библиотеки: структура, архитектура и применение
Анализ сущностей программ на языках Си/Си++ и связей между ними для понимания программ
Абстрактные базовые классы
Массивы данных в языке программирования C++
Динамически загружаемые библиотеки: структура, архитектура и применение (часть 2)
i Не можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

DIFFERENCE BETWEEN THE ANNOUNCEMENT AND DEFINITION IN C AND C ++

In this article is considered distinction between « definition » and « announcement » of a class , variable or function ; describes, how to avoid non-standard errors due to incorrect «definitions» or « announcement » of a class , variable or function .

Текст научной работы на тему «Разница между объявлением и определением в c и C++»

ЭЛЕКТРОННЫЙ НАУЧНЫЙ ЖУРНАЛ «APRIORI. ^РИЯ: ЕСТЕСТВЕННЫЕ И ТЕХНИЧЕСКИЕ НАУКИ»

РАЗНИЦА МЕЖДУ ОБЪЯВЛЕНИЕМ И ОПРЕДЕЛЕНИЕМ В C И C++

Гагарин Вячеслав Юрьевич

Мордовский государственный университет им. Н.П. Огарева, Саранск

Аннотация. В данной статье рассматривается различие между «определением» и «объявлением» класса, переменной или функции в языках С/С++; рассказывается о том, как избежать возникновения нестандартных ошибок из-за неправильного «определения» или «объявления» класса, переменной или функции.

Ключевые слова: объявление, определение, C, C++, ошибка, extern, класс, функция, переменная.

DIFFERENCE BETWEEN THE ANNOUNCEMENT AND DEFINITION IN C AND C ++

Gagarin Vyacheslav Yuryevich

Ogarev Mordovia State University, Saransk

Abstract. In this article is considered distinction between «definition» and «announcement» of a class, variable or function; describes, how to avoid non-standard errors due to incorrect «definitions» or «announcement» of a class, variable or function.

Key words: announcement, definition, C, C++, error, extern, class, function, variable.

Если говорить об истории развития этих языков, то первоначально появился язык C, а уже впоследствии как развитие языка C появился и C++. Язык C оказал большое влияние на индустрию разработки программного обеспечения. С одной стороны, синтаксис многих его инструкций лежит в основе таких языков, как С++, С#, Java, PHP. С другой, он используется в качестве промежуточного в некоторых системах программирования, когда программа сначала транслируется в программу на языке С и только потом компилируется компилятором языка С для получения окончательного исполняемого модуля [1]. Для аналогичных целей используется и язык C++, но его важным отличием от языка C является поддержка технологии ООП.

В C и C++ существует одно маленькое, но важное различие между «объявлением» и «определением» класса, переменной или функции. Необходимо понимать разницу между значением этих слов, иначе вы часто будете натыкаться на странные ошибки, такие как:

undefined reference to vtable for foo (в C++)

undefined symbol foo

undefined reference to foo

При объявлении класса, функции или переменной, вы сообщаете компилятору, что есть что-то определенного типа и с определенным именем. Но компилятор сможет обработать большую часть использований данного имени без необходимости полного определения этого имени. То есть можно объявить то или иное значение, не определив его. Это позволяет писать код, понятный компилятору, опуская дополнительные детали. Удобно это в том случае, если при работе с несколькими исходными файлами, вы должны использовать функцию в нескольких

файлах. То есть можно объявить функцию, но писать тело функции в каждом из файлов не нужно.

Иными словами, «объявление» выглядит так:

Оно не включает тело функции, но сообщает компилятору, что она (функция) будет определена где-то позже, поэтому компилятор может использовать её.

А вот «определение» означает описание всей необходимой информации для создания того, что мы определяем, целиком. Описание всех полей, методов и свойств класса есть «определение» класса. Описание тела функции есть «определение» функции. Конечно, вы можете как объявлять классы, переменные или функции, так и определять их одновременно. Но вам это не нужно, потому что, как только что-то определено, оно считается и объявленным.

Для компилятора часто достаточно просто «объявления».

double a = function();

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

Объявим класс, не определяя его:

Попробуем узнать, что находится в MyFirstClass. Напишем следующий код:

class MyFirstClass; MyFirstClass aza_obj;

Данный фрагмент кода вызовет ошибку, потому что компилятор не знает размер переменной aza_obj, а из «объявления» MyFirstClass он его узнать не может; ему нужно «определение», которое появляется ниже.

В большинстве случаев, когда вы объявляете переменную, вы также определяете ее. Поэтому «определение» переменной означает, что вы говорите компилятору, где выделить место для хранения этой переменной.

Напишем такой код:

Строка double х и определяет, и объявляет переменную. На более простом языке это означает: «создать переменную с именем х, типа double». При этом место, где хранится переменная, определяется тем, что это глобальная переменная, определенная в объектный файл, связанный с этим исходным файлом.

Создадим второй исходный файл, имеющий такой исходный код:

extern double x;

Использование extern позволяет объявить переменную, не определяя ее, extern сообщает, что переменная находится где-то в другом месте. Спецификатор extern играет большую роль в программах, состоящих из многих файлов. В языках СЮ++ программа может быть записана в нескольких файлах, которые компилируются раздельно, а затем компонуются в одно целое. В этом случае необходимо как-то сообщить всем файлам о глобальных переменных программы. Самый лучший (и наиболее переносимый) способ сделать это — определить (описать) все глобальные переменные в одном файле и объявить их со спецификатором extern в остальных файлах [2].

Напишем следующий код:

extern double x;

В данном примере «определение» переменной x находится внизу, а «объявление» в верхней части программы.

Если в заголовке файла поставить переменную и не использовать extern, то возникнет обратная задача неопределенного символа [3], то есть у вас будет символ с несколькими определениями с ошибкой типа:

redefinition of foo

Это произойдет, когда компоновщик будет связывать объектные файлы.

В общем случае «объявление» предоставляет основные свойства символа: название и тип. «Определение» предоставляет все детали этого символа — если это класс, то какие у него методы, поля и свойства; если это функция, то что она вычисляет; если это переменная, то где эта переменная хранится. Часто компилятору нужно «объявление», чтобы скомпилировать файл в объектный файл, так как компоновщик может найти «определение» из другого файла. Если исходный файл объявлен, но символ он не определяет, то во время компоновки будут возникать ошибки, сообщающие о неопределенных символах [4].

Если вы хотите использовать функцию в нескольких исходных файлах, вы должны объявить функцию в одном заголовочном файле (.h), а затем определить функцию в одном исходном файле (.с или .cpp). Весь код, который использует функция должен включать в себя только .h файл, и вам надо связать полученные объектные файлы с объектным файлом от компиляции исходного файла.

Если вы хотите использовать переменную в нескольких файлах, вы должны объявить переменную с помощью ключевого слова extern в одном заголовочном файле, а затем включить этот заголовочный файл во все исходные файлы, которым нужна эта переменная. Затем вы должны

определить эту переменную в одном исходном файле, который связан со всеми объектными файлами, которые используют эту переменную.

Если вы хотите использовать класс в нескольких файлах, вы должны поместить «определение» класса в заголовочный файл и определить методы класса в соответствующем исходном файле.

Список использованных источников

1. Александров Э.Э., Афонин В.В. Введение в программирование на языке С. Саранск: Изд-во Мордов. ун-та, 2009. 5 с.

2. Александров Э.Э., Афонин В.В. Программирование на языке С в Microsoft Visual Studio 2010 [Электронный ресурс]. Режим доступа: http://www.intuit.ru/department/pl/prcmsvs2010 (дата обращения: 25.11.2015).

3. Таненбаум Э. Современные операционные системы. СПб., 2010. 972 с.

4. Прата С. Язык программирования С. Лекции и упражнения. М.: Ви-льямс, 2006. 256 с.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *