Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.67/21: Рейтинг темы: голосов - 21, средняя оценка - 4.67
Велосипедист...
 Аватар для Mournful Max
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785

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

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

Студворк — интернет-сервис помощи студентам
Не совсем понимаю процесс раздельной компиляции, или то как работает связывание 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
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.09.2017, 13:34
Ответы с готовыми решениями:

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

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

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

70
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 17:35
Студворк — интернет-сервис помощи студентам
hoggy,
C++
1
2
3
4
namespace {
    
    static int a = 20;
}
тут ведь совсем не обязательно static приписывать? получается, что мы совмещаем сишный и плюсовый подход касательно внутреннего связывания, хотя достаточно выбрать одно из двух
(либо безымянный namespace, либо static)
1
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.09.2017, 17:35
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Константа в отличии от переменной не имеет адреса.
что ж мой компилятор, зараза такая, тогда мне адрес показывает?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
int main()
{
    int f;
    
    std::cin >> f;
    
    const int u = f;
    const int l = 123;
    
    std::cout << &f << "\n" << &l << "\n";
}
это у енумов нет адресов и вычисляются они всегда на этапе компиляции, поэтому адресов и нету.
а у констант есть, они ничем не отличаются от обычных переменных, кроме того факта, что их изменять нельзя.

P.S. если я не прав, то приведите пункт стандарта, где мой выпад распадается в пух и прах.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 18:30
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
тут ведь совсем не обязательно static приписывать?
да.

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

Добавлено через 14 секунд
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
тут ведь совсем не обязательно static приписывать?
да.

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

Добавлено через 9 минут
Цитата Сообщение от GbaLog- Посмотреть сообщение
это у енумов нет адресов и вычисляются они всегда на этапе компиляции, поэтому адресов и нету.
а теперь правильный ответ:
и у литерных, и у числовых, и у енумовских констант можно брать адрес.
равно как у константной переменной.

в этом моменте, между вторым и тьретьим разницы вообще нет никакой.
между константной переменной и числовой константой (или енумом)
различие заключается в том,
что адрес у них можно срисовать лишь опосредованно,
через ссылку:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
 
enum eVALUE { eSAMPLE };
 
template<class type>
const type* addr(const type& val)
{
    return &val; // ok
}
 
int main()
{
    const int v = 10;
    
    std::cout << &v; //ok
    std::cout << &"ololo"; //ok
    
    //error: lvalue required as unary ‘&’ operand
    //std::cout << &10;      
    
    //error: lvalue required as unary ‘&’ operand
    //std::cout << &eSAMPLE;   
    
    std::cout << addr(10); //ok
    std::cout << addr(eSAMPLE); //ok
}
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.09.2017, 19:31
Цитата Сообщение от hoggy Посмотреть сообщение
C++
1
2
3
4
5
template<class type>
const type* addr(const type& val)
{
* * return &val; // ok
}
э-хе, вообще-то тут возвращается адрес локального объекта val.
так что нет адресов у них, они подставляются в коде.
у строковых литералов можно брать адрес потому, что они особенные и это такая оптимизация, что они располагаются в статической памяти. но это тоже происходит не всегда.
слышал о случаях, когда они просто в ассемблер встраивались обычными числами.
0
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
07.09.2017, 19:32
DrOffset, Раздельная компиляция. Связывание const-переменных
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.09.2017, 19:37
Цитата Сообщение от GbaLog- Посмотреть сообщение
э-хе, вообще-то тут возвращается адрес локального объекта val
здесь нет никакого "локального объекта val"
есть аргумент-ссылка 'val' которая обозначает объект,
переданный в функцию снаружи.

операция взятия адреса у ссылки - есть операция
взятия адреса у оргинального объекта.

возвращаемый указатель будет хранить адрес объекта,
переданного в функцию.

Цитата Сообщение от GbaLog- Посмотреть сообщение
у строковых литералов можно брать адрес потому, что они особенные и это такая оптимизация, что они располагаются в статической памяти. но это тоже происходит не всегда.
оптимизации - вторичны.
синтаксис- первичен.

адрес литерной строки можно брать просто потому,
что можно - таковы правила игры.
всегда.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.09.2017, 19:46
Цитата Сообщение от hoggy Посмотреть сообщение
переданный в функцию снаружи.
передаётся rvalue, у rvalue нельзя брать адрес, как бы на этом спор можно кончить.
по не константной ссылке попробуйте передать и как бы будет как бы ошибка как бы компиляции.
константная ссылка просто продлевает жизнь объекта, который создаётся на входе в функцию.
это всё.
никаких адресов у rvalue не существует, с точки зрения стандарта.
http://en.cppreference.com/w/c... e_category
Цитата Сообщение от cppreference
rvalue
An rvalue expression is either prvalue or xvalue.
Properties:
- Address of an rvalue may not be taken: &int(), &i++[3], &42, and &std::move(x) are invalid.
Цитата Сообщение от hoggy Посмотреть сообщение
адрес литерной строки можно брать просто потому,
что можно - таковы правила игры.
я и не спорю, только вот если адрес этой константы не нужен, то его не за чем генерировать даже.
компилятор вправе применить оптимизации, если это никак не повлияет на результат программы.
0
Велосипедист...
 Аватар для Mournful Max
353 / 220 / 73
Регистрация: 15.12.2015
Сообщений: 785
07.09.2017, 20:02  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
она итак будет с внешним связыванием
Не согласен. Приведу пример.
Вариант 1:
const_test.h
C++
1
2
3
4
5
6
7
#ifndef CONST_TEST_H_
#define CONST_TEST_H_
 
int var = 10;  // oops!
void func();
 
#endif  // CONST_TEST_H_

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

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

Вариант 2:
const_test.h
C++
1
2
3
4
5
6
7
#ifndef CONST_TEST_H_
#define CONST_TEST_H_
 
const int var = 10;  // all right!
void func();
 
#endif  // CONST_TEST_H_

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

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

Первый вариант вызывает ошибку компиляции, а второй вариант компилируется успешно, создаются две независимые переменные var.
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
07.09.2017, 21:22
Вот две полезные темы, для внимательного прочтения:
Несколько *.cpp и глобальные переменные
Extern в C/C++
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.09.2017, 02:08
Цитата Сообщение от GbaLog- Посмотреть сообщение
передаётся rvalue, у rvalue нельзя брать адрес, как бы на этом спор можно кончить.
rvalue - способ доступа к объекту.
и не более того.
в представленном мой способе, передается lvalue.
rvalue прекрасно конвертится в lvalue,
когда lvalue - обозначает константу.
при этом адрес самого объекта никак не меняется.

а компилятор, видя, факт самой возможности взятия адреса,
обязан честно наделить константу этим самым адресом - расположить объект по адресу,
который честным образом можно взять.

Добавлено через 1 минуту
Цитата Сообщение от Captain Maxee Посмотреть сообщение
Не согласен. Приведу пример.
мне не очевидно с чем именно вы не согласны,
и что именно вы хотели показать своими примерами
0
70 / 70 / 35
Регистрация: 06.07.2016
Сообщений: 415
08.09.2017, 07:52
Fulcrum_013,
Неверно.
Константа является обычной переменной, для которой выделяется память, а не подставляемым значением, если :
1.Где либо в программе берется ее адрес.
2.Она является "внешней констаной", объявленной с extern.
3.В некоторых других случаях, о которых непосредственно можно узнать из документации компилятора.

"Философия С++", Брюс Эккель.
0
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
08.09.2017, 18:26
Цитата Сообщение от hoggy Посмотреть сообщение
а теперь правильный ответ:
и у литерных, и у числовых, и у енумовских констант можно брать адрес.
Числовой литерал это последовательность цифр (плюс всякие префиксы, вроде 0x, но для простоты забудем про них). Что такое адрес числового литерала? Смещение в файле с исходным кодом?

Цитата Сообщение от hoggy Посмотреть сообщение
что адрес у них можно срисовать лишь опосредованно,
через ссылку
Не работает. Вообще бред выдает. У 10 и 11 один адрес?! Почему 10 не лежит по своему адресу? Бред.....

https://wandbox.org/permlink/K7BSiLhI9m2m4327
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
template<class type>
const type* addr(const type& val)
{
    return &val;
}
 
int main()
{
    std::cout << addr(10) << '\n';
    std::cout << addr(11) << '\n';
    
    const int* addr_of_10 = addr(10);
    
    std::cout << *addr_of_10 << '\n';
}
Вывод:
Code
1
2
3
0x7ffcd2adad7c
0x7ffcd2adad7c
0
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.09.2017, 18:37
Цитата Сообщение от УГнетатель Посмотреть сообщение
Что такое адрес числового литерала?
адрес объекта.
ваш К. О.

Цитата Сообщение от УГнетатель Посмотреть сообщение
Не работает.
gcc вестимо лажает.

http://rextester.com/KIKT98113
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,407
08.09.2017, 18:48
Цитата Сообщение от Captain Maxee Посмотреть сообщение
C++
1
extern const int var; // Это почему работает?
А почему бы этому и не работать? Это обычное объявление const переменной с внешним связыванием.

Цитата Сообщение от Captain Maxee Посмотреть сообщение
C++
1
2
3
#include "const_test.h"
 
const int var = 10; // var имеет внутреннее связывание
Нет. var имеет внешнее связывание. Так как вы включили const_test.h в const_test.cpp, в этом месте видно предыдущее объявление var как переменной с внешним связыванием. Оно теперь так и останется внешним, как было изначально объявлено. "Отменить" внешнее связывание уже не получится.

А в main вы просто успешно линкуетесь к этой переменной с внешним связыванием.

А вот если убрать включение const_test.h именно из const_test.cpp, тогда это определение в const_test.cpp действительно создаст переменную с внутренним связыванием и программа перестанет линковаться.
1
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
08.09.2017, 19:07
Цитата Сообщение от hoggy Посмотреть сообщение
адрес объекта.
Речь шла про литералы. Откуда вдруг объекты взялись?

Цитата Сообщение от hoggy Посмотреть сообщение
gcc вестимо лажает.
Не сильно больше, чем vc++
http://rextester.com/DPFY59334

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
template<class type>
const type* addr(const type& val)
{
    return &val;
}
 
int main()
{
    std::cout << addr(10) << '\n';
    std::cout << addr(11) << '\n';
}
Вывод:
Code
1
2
3
4
5
/LIBPATH:C:\boost_1_60_0\stage\lib 
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
 
0000007D4EFCF930
0000007D4EFCF930
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.09.2017, 19:19
Цитата Сообщение от УГнетатель Посмотреть сообщение
Не сильно больше, чем vc++
очевидно жеж - оптимизации влияют.
уберите ключик /Ox

Добавлено через 1 минуту
Цитата Сообщение от УГнетатель Посмотреть сообщение
Речь шла про литералы. Откуда вдруг объекты взялись?
литералы - это такие "литеральные объекты".
вполне себе полноценные.
внезапно?
0
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
08.09.2017, 19:30
Цитата Сообщение от hoggy Посмотреть сообщение
очевидно жеж - оптимизации влияют.
Очевидно только одно: у числовых литералов нельзя брать адрес. &10 не скомпилируется. Вне зависимости от оптимизаций. Спорить с этим бессмысленно.

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

Цитата Сообщение от hoggy Посмотреть сообщение
литералы - это такие "литеральные объекты".
В нашем дорогом и уважаемом стандарте языка словосочетание literal object нашлось только 1 (один) раз, в разделе про строковые литералы. Вот у них (строковых литералов) можно брать адрес, так как за строковым литералом стоит литеральный объект. причём он имеет static storage duration. Этот объект, естественно, имеет адрес.

За литералом 10 самим-по-себе нет никакого объекта. И адрес у него взять нельзя.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.09.2017, 19:34
Цитата Сообщение от УГнетатель Посмотреть сообщение
Очевидно только одно: у числовых литералов нельзя брать адрес
хотите сказать, что код в #35 содержит UB?

Цитата Сообщение от УГнетатель Посмотреть сообщение
За литералом 10 самим-по-себе нет никакого объекта.
функция
C++
1
2
template<class type>
const type* addr(type&& val)
с вами не согласна
0
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
08.09.2017, 19:37
УГнетатель, хз, может быть это что то прояснит:
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,407
08.09.2017, 20:30
Лучший ответ Сообщение было отмечено GbaLog- как решение

Решение

Тема "литералов" и "взятия адреса" тут уже много раз обсуждалась.

Оператор взятия адреса разрешается применять только к lvalue-выражениям.

Выражение, состящее из имени переменной либого типа (константной или нет) является lvalue, поэтому его адрес можно брать.

Выражение, состящее из имени enum-константы не является lvalue, поэтому его адрес брать нельзя. У enum-константы никакого адреса нет и быть не может.

Выражение, состящее из встроенного литерала, не является lvalue, поэтому его адрес брать нельзя (за исключением строковых литералов). У числового литерала никакого адреса нет и быть не может.

Выражение, состящее из строкового литерала, является lvalue. У строковых литералов есть адреса.
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.09.2017, 20:30

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
Генератор паролей (вариант №2)
Maks 30.10.2026
Обновленная версия ранее созданной обработки. Добавлены следующие реквизиты типа Булево: - Буквы; - Цифры; - Символы. Изменена логика команды "Сгенерировать" и процедуры "ПриОткрытии":. . .
Генератор паролей (вариант №1)
Maks 29.10.2026
Реализация из решения ниже выполнена исключительно по моей инициативе, дабы облегчить себе работу в создании паролей для администрируемых мною сервисов и пользователей. Самым главным критерием для. . .
Установка ChatGPT (Codex) на Windows без использования Microsoft Store
Fabien159 28.10.2026
Здравствуйте всем читающим! Опишу процесс установки ChatGPT (Codex) на Windows, если по каким-то причинам у вас не получается устанавить его через Microsoft Store. И так: 1. Скачиваем с. . .
Программное добавление префикса в нумерацию документов
Maks 27.10.2026
Реализация из решения ниже выполнена в самописной конфигурации на БСП (помощь начинающему коллеге). Задача: Программно добавить префикс в нумерацию документов. Решение: В модуле объекта. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru