Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
1

Раздельная компиляция. Связывание const-переменных

07.09.2017, 13:34. Показов 3646. Ответов 70
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Не совсем понимаю процесс раздельной компиляции, или то как работает связывание const-переменных. Имеется три файла:
const_test.h
C++
1
2
3
4
5
6
7
#ifndef CONST_TEST_H_
#define CONST_TEST_H_
 
extern const int var;  // Это почему работает?
void func( void );
 
#endif  // CONST_TEST_H_

const_test.cpp
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
#include "const_test.h"
 
const int var = 10;  // var имеет внутреннее связывание
 
void func( void )
{
    std::cout << &var << std::endl;
}

general.cpp
C++
1
2
3
4
5
6
7
8
#include <iostream>
#include "const_test.h"
 
int main()
{
    std::cout << &var << std::endl;
    func();
}

Собственно, почему это не вызывает ошибку компиляции? ( Компилировал в VS 2013 ) Разве не должен был произойти конфликт имен, когда в файл "const_test.cpp" включился файл "const_test.h"? Ведь, как я понимаю, extern const int var; -- это отличная переменная от const int var = 10;. Теперь немного изменим код:
const_test.h
C++
1
2
3
4
5
6
7
#ifndef CONST_TEST_H_
#define CONST_TEST_H_
 
extern int var;
void func( void );
 
#endif  // CONST_TEST_H_

const_test.cpp
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
#include "const_test.h"
 
static int var = 10;
 
void func( void )
{
    std::cout << &var << std::endl;
}

general.cpp
C++
1
2
3
4
5
6
7
8
#include <iostream>
#include "const_test.h"
 
int main()
{
    std::cout << &var << std::endl;
    func();
}

Это уже ошибка. И это, по-моему нормально ( а по законам C++ нет? ), ведь инструкция extern int var; 1) порождает конфликт имен, 2) ссылается на несуществующую переменную ( ведь ни в одной единице трансляции не была объявлена внешняя int переменная с именем var ). В коде изменилось ( опять же таки, по моему мнению ) только то, что переменная var перестала быть const.

P.S.: Знаю, что не умею доступно объяснять, но у здешних жителей форума, как показывает практика, хорошо развиты телепатические способности, проблем возникнуть не должно
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.09.2017, 13:34
Ответы с готовыми решениями:

Раздельная компиляция
Здравствуйте, я перечитал на форуме информацию по этой теме, но пока что не сумел разобраться. У...

Раздельная компиляция
Пусть есть программа, которая состоит из 2 файлов. 1 файл: основной, там где main 2 файл:...

раздельная компиляция
Вот есть три файла: заголовочный файл с классом (.h), файл с реализацией методов класса (.cpp), и...

Раздельная компиляция
В Гугле не забанен,нашел описание самого принципа,но конкретных примеров не нашел. Вопросы вот...

70
805 / 532 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 14:04 2
Тоже хотел бы увидеть ответ, наверное опять чтото в стандарте прописано касательно констант
1
Любитель чаепитий
3742 / 1798 / 566
Регистрация: 24.08.2014
Сообщений: 6,016
Записей в блоге: 1
07.09.2017, 14:09 3
Цитата Сообщение от Captain Maxee Посмотреть сообщение
// var имеет внутреннее связывание
если оно в хедере объявлено, как extern, то с чего оно вдруг связывание станет внутренним?
Цитата Сообщение от Captain Maxee Посмотреть сообщение
static int var = 10;
а вот тут уже внутреннее связывание, в итоге ошибка компиляции, т.к. var нигде не определяется, но есть попытка использования объявленной переменной.

Добавлено через 2 минуты
в догонку: https://habrahabr.ru/post/150327/
1
805 / 532 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 14:14 4
в первой версии файла const_test.cpp в 4ой строке
C++
1
const int var = 10;
с учетом включения const_test.h эквивалентно
C++
1
extern const int var = 10;
?
1
672 / 475 / 215
Регистрация: 06.09.2013
Сообщений: 1,306
07.09.2017, 14:23 5
Цитата Сообщение от Captain Maxee Посмотреть сообщение
В коде изменилось ( опять же таки, по моему мнению ) только то, что переменная var перестала быть const.
static появилось, а это внутреннее связывание, убрать его и не будет ошибки, разве не так?
1
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 14:31  [ТС] 6
GbaLog-,
Цитата Сообщение от GbaLog-
если оно в хедере объявлено, как extern, то с чего оно вдруг связывание станет внутренним?
Ну, потому что const int var = ?;, == static const int var = ?;.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 14:32 7
Цитата Сообщение от Captain Maxee Посмотреть сообщение
В коде изменилось ( опять же таки, по моему мнению ) только то, что переменная var перестала быть const
нет не только.
и дело вовсе не в квалификаторе const

Цитата Сообщение от Captain Maxee Посмотреть сообщение
const int var = 10;
Цитата Сообщение от Captain Maxee Посмотреть сообщение
static int var = 10;
во втором случае переменная объявляется как статическая.
это значит, что область её видимости
принудительно ограничивается одной ед. трансляции.

а значит инструкция: extern int var
уже не имеет к ней никакого отношения.

поэтому, для соседней ед. трансляции
глобальная переменная по прежнему остается объявленной,
но неопределенной.

а в первом случае все как обычно:
C++
1
2
3
4
// дорогой компилятор,
// эта хрень определена где-то "там"
// в одной из единиц трансляций
extern const int var;
C++
1
2
3
4
// дорогой компилятор,
// здесь я определяю значение 
// глобальной хрени
const int var = 10;
1
805 / 532 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 14:34 8
hoggy, почему в 1ом коде
C++
1
const int var = 10;
неявно канает как
C++
1
extern const int var = 10;
?
1
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 14:37 9
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
почему в 1ом коде
остановок "здеся" и "тута" не существует.
0
805 / 532 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 14:38 10
hoggy, в первой версии const_test.cpp из 1ого поста
0
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 14:48  [ТС] 11
hoggy,
Цитата Сообщение от hoggy
а в первом случае все как обычно:
Стивен Прата говорит, что переменная с квалификатором const, объявленная вне функции/класса/другого блока, по умолчанию имеет внутреннее связывание.
C++
1
2
extern const int var = ?;  // имеет внешнее связывание
const int var = ?;  // эквивалентно static const int var = ?;
Как-то так он это описал. Могу главу сказать и подраздел, если потребуется.
Я, собственно, из-за этого и задал вопрос. Книга написана на основе C++11. Может, в новом стандарте, все по-другому?
Это я сейчас не оспариваю, а просто уточняю.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 15:10 12
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
в первой версии const_test.cpp из 1ого поста
см #7

Цитата Сообщение от Captain Maxee Посмотреть сообщение
переменная с квалификатором const, объявленная вне функции/класса/другого блока, по умолчанию имеет внутреннее связывание.
ключевые слова: "объявленная" и "по умолчанию"

в вашем случае: extern const int var; - это явное (больше уже никаких "умолчаний")
объявление переменной с внешним связыванием.

в то время как последующая за ней запись:
const int var = 10; - это уже определение переменной
объявленной ранее как с внешним связыванием.

постречав её, компилятор вспоминает, что недавеча видел её объявление,
и понимает, что вот конкретно для неё связывание должно быть внешним.
2
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 15:22  [ТС] 13
hoggy, тогда какая разница между:
C++
1
2
extern const int var;
extern const int var = 10;
… и:
C++
1
2
extern const int var;
const int var = 10;
0
805 / 532 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 15:24 14
А вобще может такое быть, чтобы некая сущность со внутренним связыванием скрывала сущность с тем же именем, имеющую внешнее связывание?
0
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 15:29  [ТС] 15
hoggy,
P.S.: Просто в книге сказано, что применение extern к определению const-переменной, дает ей внешнее связывание ( по умолчанию связывание внутрннее ).
Применение extern к объявлению const-переменной, говорит компилятору, что где-то есть определение этой переменной ( в общем, как обычно это бывает ).
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
07.09.2017, 15:41 16
что бы понять, удаляем хедер и оставляем два .cpp
C++
1
2
3
4
/*source1.cpp*/
#include <iostream>
extern int var;
int main() { std::cout << var << std::endl; return 0; }
C++
1
2
/*source2.cpp*/
int var = 10;
если const то тут и во втором файле надо явно указать extern, так как:
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Стивен Прата говорит, что переменная с квалификатором const, объявленная вне функции/класса/другого блока, по умолчанию имеет внутреннее связывание.
1
2063 / 1542 / 168
Регистрация: 14.12.2014
Сообщений: 13,402
07.09.2017, 15:59 17
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Не совсем понимаю процесс раздельной компиляции, или то как работает связывание const-переменных. Имеется три файла:
const это не переменная а константа, она должна инициализироваться при объявлении.
Константа в отличии от переменной не имеет адреса. Ее значение вшивается непосредственно в кота, при этом если в выражении имеются другие константы, константная часть вычисляется на этапе компиляции.
Соответсвенно ни о каком связывании констант при раздельной компиляции речи быть просто не может. Константа просто объявляется и инициализируется в хидере.
1
2063 / 1542 / 168
Регистрация: 14.12.2014
Сообщений: 13,402
07.09.2017, 16:21 18
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Говоря const-переменная, я имею ввиду переменную, объявленную с квалификатором const
Ну вот с квалификатором const константы и объявляются.

Добавлено через 1 минуту
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Если объявить ее, а не определить, это будет трактоваться как ссылка на переменную в другой единице трансляции
Ее нельзя не определить. Константа должна быть определена при объявлении.
1
Велосипедист...
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 16:37  [ТС] 19
Operok, да, я это понимаю. Сейчас попробую в очередной раз разъяснить ситуацию, чтобы вы поняли, чего я хочу.
Я понимаю, что определенная вне всех блоков переменная, по умолчанию имеет внешнее связывание.
Я понимаю, что нужно использовать спецификатор extern в объявлении той самой переменной, чтобы использовать ее в другой единице трансляции.
Я понимаю, что объявленная вне всех блоков переменная со спецификатором static, имеет внутреннее связывание.

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

Собственно, исходя из этих утверждений, const int var = 10 == static const int var = 10. Инструкция extern const int var должна искать следующее определение: extern const int var = 10, а не const int var = 10 ( ибо здесь внутреннее связывание ).

Исходя из слов hoggy, я рассуждаю неверно. Поправьте меня, где ошибаюсь.

Добавлено через 2 минуты
Fulcrum_013,
Цитата Сообщение от Fulcrum_013
Константа в отличии от переменной не имеет адреса.
Говоря const-переменная, я имею ввиду переменную, объявленную с квалификатором const.

Не по теме:

Дайте интернета, иначе я сломаю стол.

0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 17:28 20
Цитата Сообщение от Captain Maxee Посмотреть сообщение
тогда какая разница между:
никакой.
если не считать, что в первом случае ключевое слово extern
для определения переменной является избыточным.

Цитата Сообщение от Ferrari F1 Посмотреть сообщение
А вобще может такое быть, чтобы некая сущность со внутренним связыванием скрывала сущность с тем же именем, имеющую внешнее связывание?
технически - да.
объявить такие переменные можно.
а вот использовать - не получится.
компилятор пофиксит неоднозначность:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
extern int a;
 
 
int a = 10;
 
namespace {
    
    static int a = 20;
}
 
int main()
{
    //error: reference to ‘a’ is ambiguous
    std::cout << "a = " << a << '\n';
}
Добавлено через 2 минуты
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Просто в книге сказано, что применение extern к определению const-переменной, дает ей внешнее связывание
это избыточно.
она итак будет с внешним связыванием,
если была таковой объявлена.

Добавлено через 4 минуты
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Ее нельзя не определить. Константа должна быть определена при объявлении.
вам стоит подучить с++
1
07.09.2017, 17:28
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.09.2017, 17:28
Помогаю со студенческими работами здесь

Шаблоны и раздельная компиляция
Здравствуйте! Если просто я пишу класс, например: class Test { private: int *pm; ...

Раздельная компиляция файлов
Если класс определен в раздельных файлах и изменения сделаны в части main программы, кот использует...

Раздельная компиляция и шаблоны
Есть 3 файла с кодом: 1) foo.hpp template&lt;typename T&gt; class foo { public: T bar; foo();...

Раздельная компиляция и шаблоны
привет. возьму вот такой выдуманный пример #ifndef CCLASS_H #define CCLASS_H #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru