постоянный и глобальный - PullRequest
       48

постоянный и глобальный

1 голос
/ 27 января 2012

Этот код выдаст ошибку в c ++

// Foo.cpp
const int Foo = 99;

// Main.cpp
extern const int Foo;
int main()
{
    cout << Foo << endl;
    return 0;
}    

Причина, указанная многими, заключается в том, что глобальное const имеет внутреннюю область действия и является статическим по умолчанию.

решение этого вопроса: -

    //Foo.h
    extern const int Foo; 

    // Foo.cpp
    #include "Foo.h"
    const int Foo = 99; 

    // Main.cpp
    #include "Foo.h"
    int main()
    {
       cout << Foo << endl;
    }

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

Ответы [ 2 ]

7 голосов
/ 27 января 2012

Что если мы должны объявить только глобальную константу (не static)?Как extern помогает в этом?

Объект const, объявленный с квалификатором extern, имеет внешнюю связь.
Так что если вы хотите использовать const для нескольких единиц переводадобавьте к нему квалификатор extern.

Хотя глобальная переменная по умолчанию имеет внешнюю связь, почему const global по умолчанию имеет внутреннюю связь?

Ссылка:
C ++ 03Стандартное приложение C Совместимость C.1.2 Пункт 3: основные понятия

Изменение: Имя области действия файла, которая явно объявлена ​​как const, а не явно объявлена ​​как extern, имеетвнутренняя связь, в то время как в C она будет иметь внешнюю связь

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


Избегайте путаницы, следуя простому правилу:

По умолчанию Linkageявляется внешним для неконстантных символов и статическим (внутренним) для константных символов.

3 голосов
/ 27 января 2012

Быстрое напоминание, чтобы было понятно, о чем мы говорим:

int const a;            //  illegal
int const a = 42;       //  definition, internal linkage
extern int const a;         //  declaration, external linkage
extern int const a = 42;    //  definition , external linkage

Обратите внимание, что без const первые два объявления выше оба определения с внешней связью. Это не ортогональное, а не очень интуитивно, но это то, что говорят текущие правила.

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

Конечно, это не вызывает никаких проблем с шаблонами, по крайней мере теоретически; следующий заголовок имеет неопределенное поведение, если это в том числе в нескольких переводческих единицах:

#include <std::vector>

int const fixedValue = 42;
inline void insertFixedValue( std::vector<int>& dest )
{
    dest.push_back( fixedValue );
}

Стандарт гласит, что не только встроенные функции и шаблоны должны иметь идентичная последовательность токенов, но все символы должны связываться к одному и тому же объекту в каждой единице перевода, или есть нарушение одно определение правила. А так как fixedValue не имеет внешнего связь, есть уникальный экземпляр в каждой единице перевода. (Есть исключение , если символ относится к const объекту и немедленное преобразование lvalue в rvalue. поскольку std::vector<int>::push_back принимает аргумент в качестве ссылки, однако, нет непосредственного преобразования lvalue в rvalue, и мы получаем неопределенное поведение.)

И, конечно же, любой с шаблоном:

template <int& r> ...

также не может создать экземпляр с fixedValue.

Причина внутренней связи, конечно, историческая. Сегодня, Компиляторы должны поддерживать такие вещи, как:

struct X
{
    static int const a = 42;    //  declaration!!!, external linkage
};

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

int const a;                //  illegal
int const a = 42;           //  definition, external linkage
extern int const a;         //  declaration, external linkage
extern int const a = 42;    //  declaration, external linkage

Это восстановит ортогональность (даже если это потребует дополнительного набора текста). Это также нарушит почти весь существующий код.

Другой альтернативой будет обработка const определений переменных точно так же, как шаблоны функций обрабатываются сегодня: вы можете иметь несколько определения, но все они должны быть идентичны. Это, вероятно, позволит избежать большинство, если не все, поломка кода.

...