2016-12-15 21 views
0

Изучение с this: По умолчанию переменные, не объявленные вне блока, считаются внешними. Однако константные переменные, объявленные вне блока, считаются внутренними.Не по умолчанию не является переменной const?

Но если я пишу это в MyTools.h:

#ifndef _TOOLSIPLUG_ 
#define _TOOLSIPLUG_ 

typedef struct { 
    double LN20; 
} S; 

S tool; 

#endif // !_TOOLSIPLUG_ 

и включаю MyTools.h 3 раза (с 3-х различных .cpp) он говорит, что tool уже определен (на этапе линкера). Только если я изменю в:

extern S tool; 

работает. Не является внешним по умолчанию?

+0

Ваша проблема не в переменной, а в файле заголовка. –

+0

Попробуйте использовать в начале h-файла: #pragma once –

+0

У меня уже есть защита заголовка – markzzz

ответ

3

Объявление S tool; в области пространства имен, объявляет переменную связи extern. Он также определяет его. И в этом проблема, поскольку вы делаете это в трех разных единицах перевода: вы говорите компоновщику, что у вас есть случайно назвал три разных глобальных переменных одного и того же типа.


Одним из способов достижения эффекта вы, кажется, желание, единая глобальная общие переменные, объявленные в заголовке, чтобы сделать это:

inline auto tool_instance() 
    -> S& 
{ 
    static S the_tool; // One single instance shared in all units. 
    return the_tool; 
} 

static S& tool = tool_instance(); 

Функция-доступ к-а-местного статический называется одноэлемент Мейерса, после Скотта Мейерса.

В C++ 17 и более поздних версиях вы также можете просто объявить переменную inline.


Следует учитывать, что глобальные переменные считаются Evil™. Цитирование Wikipedia on that issue:

Использование глобальных переменных делает программное обеспечение труднее читать и понимать. Поскольку любой код в любом месте программы может в любой момент изменить значение переменной, понимание использования переменной может повлечь за собой понимание значительной части программы. Глобальные переменные затрудняют разделение кода на многоразовые библиотеки. Они могут привести к проблемам именования, поскольку глобальная переменная, определенная в одном файле, может конфликтовать с тем же именем, которое используется для глобальной переменной в другом файле (что приводит к сбою связи). Локальная переменная с тем же именем может защитить глобальную переменную от доступа, что опять-таки приведет к созданию более сложного кода. Настройка глобальной переменной может создавать побочные эффекты, которые трудно найти и предсказать. Использование глобальных переменных затрудняет выделение единиц кода для целей модульного тестирования; таким образом, они могут непосредственно способствовать снижению качества кода.

Отказ от ответственности: код не трогать руками компилятора.

+0

Я вижу. Но почему, если я написал 'extern S tool', в .h, он не определяет его, а просто объявляет? Это нормально? – markzzz

+0

Да, 'extern S tool' просто объявляет об этом, и да, это гарантировано стандартом. –

+0

О, круто! Не знал! Благодаря! – markzzz

0

По умолчанию неконстантных переменных, объявленных вне блока считаются внешними. Однако константные переменные, объявленные вне блока, считаются внутренними.

Это утверждение по-прежнему верно в вашем случае.

В вашем MyTools.h, tool внешний.

S tool; // define tool, external scope 

В файле cpp, однако, extern ключевое слово просто означает, что S определяется еще где.

extern S tool; // declare tool 
1

Там разница между декларации и определения. extern in i; - это объявление: в нем указано, что существует переменная с именем i, тип которой int, и подразумевает, что она будет определена где-то в другом месте. int i;, с другой стороны, является определением переменной i. Когда вы пишете определение, он сообщает компилятору создать эту переменную. Если у вас есть определения одной и той же переменной в более чем одном исходном файле, у вас есть несколько определений, и компилятор (ну, на практике, компоновщик) должен жаловаться. Вот почему определение S tool; в заголовке создает проблемы: каждый исходный файл, который содержит этот заголовок, содержит , определяющийtool, и компилятор правильно жалуется.

Разница между const и not- const определения, как вы говорите, что const int i = 3; определяет переменную с именем i что локальный в файл компилируется. Нет проблем с тем же определением в более чем одном исходном файле, потому что у этих парней есть внутренняя связь , то есть они не видны за пределами исходного файла. Если у вас нет const, например, с int i = 3;, который также определяет переменную с именем i, но она имеет внешнюю связь , что она видна вне исходного файла и имеет одинаковое определение в нескольких файлах. вы эта ошибка. (технически это определения с таким же именем, что приводит к проблемам: int i = 3; и double i = 3.0; в двух разных исходных файлах по-прежнему являются повторяющимися определениями).