Путаница между объявлением и определением переменной в C - PullRequest
4 голосов
/ 01 марта 2011

Я новичок в C и испытываю некоторую путаницу между объявлением и определением переменной.Еще одна вещь, которую я хотел бы знать: верно ли следующее:

"Декларация появляется много раз, а определение приходит один раз."*

Это только декларация?Так как память выделена для x, тогда почему это не определение вместо объявления?

Ответы [ 2 ]

8 голосов
/ 01 марта 2011

Простое написание int x; в глобальной или локальной области означает и декларацию и определение. Как правило, объявление сообщает компилятору: «В какой-то момент эта переменная будет существовать под этим именем, поэтому вы можете использовать ее». Определение указывает компилятору на самом деле организовать создание переменной - очевидно, это может произойти только один раз.

Как правило, вы будете использовать это, добавив заголовочный файл:

// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined

extern int bar; // Declare a variable bar

#endif

И в одноместном исходном файле

#include "foo.h"
int bar; // Define bar

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

Точная семантика определена в разделе 6.9.2 стандарта C и может быть обобщена следующим образом:

  • Когда переменная объявляется в области видимости файла с инициализатором, это внешнее определение . (§6.9.2 / 1) * * 1 023
  • Когда переменная объявляется в области файла без инициализатора и без спецификатора класса хранения или с указателем static класса хранения, это предварительное определение . Если единица перевода (файл) имеет одно или несколько предварительных определений и нет внешнего определения , компилятор автоматически добавляет истинное объявление области файла в конце единицы перевода с нулем инициализатор. (§6.9.2 / 2) * * тысяча тридцать два

Это означает, что, строго говоря, int x; не является определением; но он автоматически создает определение тогда и только тогда, когда не имеет другого определения с инициализатором, и нет определения static (этот третий случай - неопределенное поведение из-за разногласий в отношении связей согласно §6.2.2 / 7)

Обратите внимание, что extern int x; не является внешним определением . Это объявление со спецификатором класса хранения extern. Таким образом, extern int x; само по себе не создает определение, но если у вас есть оба:

extern int x;
int x;

Тогда вы получите определение, созданное в некоторой точке файла.

С технической точки зрения это также допустимо:

extern int x;
int x;
int x = 42;

В этом случае int x; в середине является излишним и не имеет никакого эффекта. Тем не менее, это плохая форма, так как это сбивает с толку в этом случае, когда фактическое определение.

7 голосов
/ 01 марта 2011

Это не то, что вы видите слишком много в C, но оно работает следующим образом:

В заголовочном файле вы можете иметь такую ​​строку:

extern int x; //declaration

Потому чтомодификатора extern, это говорит компилятору, что где-то есть int с именем x .Компилятор не выделяет для него место - он просто добавляет int x в список переменных, которые вы можете использовать.Он выделит место для x только тогда, когда увидит такую ​​строку:

int x; //definition

Вы можете видеть, что, поскольку только строка int x; изменяет ваш исполняемый файл, вы можете иметь столько же extern int x;линии, как вы чувствуете, как.Пока есть только строка int x;, все будет работать так, как вы хотите - наличие нескольких объявлений ничего не меняет.

Лучший пример взят из C ++ (извините, если это только Cвопрос - это относится и к struct s, но я не знаю синтаксис на макушке):

class Pineapple; //declaration

Pineapple* ptr;  //this works
Pineapple pine;  //this DOES NOT work

Это объявление говорит компилятору, что естькласс под названием "Ананас".Он ничего не говорит нам о классе (насколько он велик, каковы его члены).Мы можем использовать указатели на Ананасы сейчас, но у нас пока нет экземпляров - мы не знаем, из чего состоит Ананас, поэтому мы не знаем, сколько места занимает экземпляр.

class Pineapple
{
public:
    int ounces;
    char* name;
}; //definition

Pineapple* ptr;   //still works
Pineapple pine;   //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;

После определения мы знаем все о классе, поэтому у нас тоже могут быть экземпляры.Как и в примере с C, вы можете иметь несколько объявлений, но только одно определение.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...