Відмінності між ініціалізацією, визначенням, оголошенням змінної


78

Прочитавши запитання , я знаю різницю між декларацією та визначенням. То чи це означає, що визначення дорівнює декларації плюс ініціалізація?


1
Ініціалізація призначена для змінних. Визначення може застосовуватися також для функцій, де ви визначаєте тіло.
FKaria

Отже, ви маєте на увазі для змінної, це правильно.
Тоні

Відповіді:


99

Декларація

Декларація, як правило, стосується введення нової назви в програму. Наприклад, ви можете оголосити нову функцію, описавши її "підпис":

void xyz();

або оголосити неповний тип:

class klass;
struct ztruct;

і останнє, але не менш важливе, щоб оголосити об’єкт:

int x;

Це описано у стандарті С ++ у пункті 3.1 / 1 як:

Декларація (пункт 7) може вводити одне або кілька імен в одиницю перекладу або перекладати імена, введені попередніми деклараціями.

Визначення

Визначення - це визначення раніше оголошеного імені (або це може бути як визначення, так і оголошення). Наприклад:

int x;
void xyz() {...}
class klass {...};
struct ztruct {...};
enum { x, y, z };

Зокрема, стандарт С ++ визначає його в §3.1 / 1 як:

Декларація - це визначення, якщо воно не оголошує функцію, не вказуючи тіло функції (8.4), не містить специфікатор extern (7.1.1) або специфікацію посилання25 (7.5), і не ініціалізатор, ані тіло функції, воно не оголошує статичний член даних у визначенні класу (9.2, 9.4), це оголошення класу імен (9.1), це непрозоре-enum-оголошення (7.2), це шаблон-параметр (14.1), це параметр- декларація (8.3.5) у деклараторі функції, яка не є декларатором визначення функції, або це декларація typedef (7.1.3), декларація псевдоніма (7.1.3), декларація використання (7.3. 3), static_assert-декларація (п. 7), атрибут-декларація (п. 7), порожня декларація (п. 7) або директива з використання (7.3.4).

Ініціалізація

Ініціалізація відноситься до "присвоєння" вартості під час побудови. Для загального об’єкта типу Tвін часто має вигляд:

T x = i;

але в C ++ це може бути:

T x(i);

або навіть:

T x {i};

з C ++ 11.

Висновок

То чи це означає, що визначення дорівнює декларації плюс ініціалізація?

Це залежить. Про те, про що ви говорите. Якщо ви говорите про об'єкт, наприклад:

int x;

Це визначення без ініціалізації. Натомість наведено визначення з ініціалізацією:

int x = 0;

У певному контексті немає сенсу говорити про "ініціалізацію", "визначення" та "декларацію". Наприклад, якщо ви говорите про функцію, ініціалізація не означає багато чого.

Отже, відповідь негативна : визначення не означає автоматично оголошення та ініціалізацію.


14
Не зовсім: int x;це визначення, а також декларація.
Енджу більше не пишається SO

2
@Angew, дякую, я додав більш повне визначення .
Взуття

Я думаю, що питання, яке згадував ОП у своєму дописі, досить добре відповідає на визначення та декларацію. Але спочатку питання було So does it mean definition equals declaration plus initialization.
Тахліл

@Tahlil, додав висновок. Дякуємо за те, що ви мене помітили.
Взуття

3
@Tony Я думаю (будь ласка, хтось виправте мене, якщо я помиляюсь, тому я дізнався) 'extern int x' робить це просто декларацією, що означає, що визначення можна знайти деінде. Хоча 'int x' насправді визначає його, хоча і призначається із випадковим значенням сміття, якщо ви не ініціалізуєте його спеціально, як 'int x = 5'.
нахабник

41

Декларація говорить "ця річ десь існує":

int foo();       // function
extern int bar;  // variable
struct T
{
   static int baz;  // static member variable
};

Визначення говорить "ця річ існує тут; створіть для неї пам'ять":

int foo() {}     // function
int bar;         // variable
int T::baz;      // static member variable

Ініціалізація є необов’язковою в точці визначення об’єктів і говорить "ось початкове значення для цієї речі":

int bar = 0;     // variable
int T::baz = 42; // static member variable

Іноді це можливо в точці декларації:

struct T
{
   static int baz = 42;
};

... але це потрапляння в більш складні функції.


Дуже добре пояснено, за винятком того, що ініціалізація є дещо складнішою, ніж це. (Це було б не C ++, якби це було так просто.) Ініціалізація включає такі речі, як нульова ініціалізація змінних зі статичним часом життя та конструктори за замовчуванням, а також те, що ви показуєте. (І, щоб додати плутанини: в C ініціалізація може бути першим, коли призначається змінна; наприклад, у висловлюваннях типу "прийняття значення неініціалізованої змінної". Мене не здивує, якщо щось із цього також проскочить в C ++.)
Джеймс Канзе,

О, і є також особливі випадки, коли C ++ дозволяє вказати ініціалізацію в декларації.
Джеймс Канце,

1
@JamesKanze: Вирішив зробити це дуже просто для цих цілей
Гонки легкості на орбіті

6

Для С, принаймні, для С11 6.7.5:

Декларація визначає інтерпретацію та атрибути набору ідентифікаторів. Визначення ідентифікатора є декларацією для цього ідентифікатора , що:

  • для об’єкта викликає зарезервоване сховище для цього об’єкта;

  • для функції включає тіло функції;

  • для константи перерахування - це (єдине) оголошення ідентифікатора;

  • для імені typedef - це перша (або єдина) декларація ідентифікатора.

За C11 6.7.9.8-10:

Ініціалізатор визначає початкове значення, що зберігається в об'єкті ... якщо об'єкт, що має автоматичне зберігання, не ініціалізується явно, його значення невизначене.

Отже, загалом, декларація вводить ідентифікатор та надає інформацію про нього. Для змінної визначення - це оголошення, яке виділяє пам’ять для цієї змінної.

Ініціалізація - це специфікація початкового значення, яке слід зберегти в об’єкті, що не обов’язково збігається з тим, коли ви явно призначили перший раз йому значення. Змінна має значення, коли ви його визначаєте, незалежно від того, явно ви надаєте йому значення. Якщо ви явно не надаєте їй значення, а змінна має автоматичне зберігання, вона матиме початкове значення, але це значення буде невизначеним. Якщо у нього є статичне сховище, воно буде неявно ініціалізоване залежно від типу (наприклад, типи покажчиків ініціалізуються до нульових покажчиків, арифметичні типи ініціалізуються до нуля тощо).

Отже, якщо ви визначите автоматичну змінну, не вказавши для неї початкове значення, наприклад:

int myfunc(void) {
    int myvar;
    ...

Ви визначаєте його (і, отже, також декларуєте, оскільки визначення є деклараціями), але не ініціалізуєте. Отже, визначення не дорівнює декларації плюс ініціалізації.


У C ++ ініціалізація значно відрізняється. (C також має еквівалент нульової ініціалізації об'єктів зі статичним часом життя.)
Джеймс Канце,

@JamesKanze: Так, на жаль, це питання позначене як C, так і C ++, що не дуже корисно щодо тих моментів, коли вони різняться.
Кроумен

Цілком. Для сумісних типів намір (принаймні спочатку) в C ++ полягав у тому, щоб вони поводились так само, як у C; насправді, я думаю, вони все одно поводяться однаково у всіх випадках, коли самі мови сумісні. Але формулювання, що використовується для визначення такої поведінки, зовсім інше.
Джеймс Канце,

1

"Отож це означає, що визначення дорівнює декларації плюс ініціалізації."

Необов’язково ваша декларація може бути без будь-якої змінної ініціалізована, як:

 void helloWorld(); //declaration or Prototype.

 void helloWorld()
 {
    std::cout << "Hello World\n";
 } 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.