Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.67/18: Рейтинг темы: голосов - 18, средняя оценка - 4.67
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855

Чертовщина с #include guards и #pragma once

25.12.2019, 19:57. Показов 4119. Ответов 41

Господа, у меня тут творится какая-то хрень: что бы я ни делал, h-файл инклудится дважды и константы, описанные в нём, в разных модулях имеют разные адреса! Рядышком, ага.



Что я делаю не так? И как это вообще можно объяснить?



----
Тестировал в CodeBlocks и DevCpp, компайлер mingw (gcc).
Вложения
Тип файла: 7z Test.7z (1.0 Кб, 5 просмотров)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.12.2019, 19:57
Ответы с готовыми решениями:

Работа с файлами в C# с исп. библиотек #include <stdio.h> #include <stdlib.h> #include <math.h> #include <io.h>
В типизированном файле записаны названия городов и их численность. Увеличить численность каждого города на 5% (Количество жителей всегда...

#include<iostream>// подключение библиотек #include <conio.h> #include <climits>
помогите для этой программы сделать блок-схему. Пожалуйста #include&lt;iostream&gt;// подключение библиотек #include &lt;conio.h&gt; ...

Чем отличается #include <cstring>, #include <string> и #include <string.h>?
Доброго времени суток :) Пишу свой класс и мне для нужны функции для работы со строками. Когда подключаю #include &lt;string&gt; все...

41
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 21:04
Цитата Сообщение от Verevkin Посмотреть сообщение
Тогда почему линкер не ругается на 2 идентификатора с одинаковыми именами?
А почему он должен ругаться? Линкер может/должен ругаться только на множественные сущности с внешним связыванием, да и то не всегда.

Вы же объявили переменные с внутренним связыванием. Они линкеру вообще не видны. А если бы и были видны, ругаться на них он все равно не имел бы права.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 21:08  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
хотя не понятно, чем тебя extern не устраивает
Я подумаю.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 21:18
Цитата Сообщение от Verevkin Посмотреть сообщение
Получается, что без extern не обойтись?
Проблема с вариантом раздельного объявления/определения для констант заключается в том, что в таком варианте значение константы не видно в точке ее объявления. То есть компилятор в общем случае будет не в состоянии оптимизировать код путем подстановки фактического значения константы. Он будет вынужден почти везде интерпретировать такую константу как обычную переменную в памяти (если исключить глобальные оптимизации на этапе линковки).

В языке С++ в том числе именно эту проблему решили путем введения inline переменных. В С же, если такие оптимизации критичны, пришлось бы вертеться как-то по-другому...

Но это все может быть критично скорее для скаляров. А вам, как я понял, в реальном коде нужен совсем не скаляр, а какой-то "тяжелый" объект. Тогда без вариантов: раздельное объявления/определение.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 21:24  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
хотя не понятно, чем тебя extern не устраивает
Наверное, потому, что его надо явно использовать. Во всех 100500 модулях проекта надо прописывать этот идентификатор. Но, блин, получается, что в двух модулях можно объявить 2 глобальных переменных с одинаковыми именами? Если понадобится их использовать как внешние в третьем модуле, то как?.....

Добавлено через 6 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Но это все может быть критично скорее для скаляров. А вам, как я понял, в реальном коде нужен совсем не скаляр, а какой-то "тяжелый" объект.
Ну да. Таблица с данными (интерполированные значения некой функции). Таблица большая. Мне нужно вшить её в код один раз (прибить гвоздями) и определить указатель на её начало (тоже прибить гвоздями). Ну и размер (кол-во) элементов.
Короче, нужно, чтоб в любом месте исходника си-программы были доступны этот указатель и размер.

А пока у меня данные дублируются и указатели содержать разные адреса.
---------
Как это лучше организовать?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 21:28
Цитата Сообщение от Verevkin Посмотреть сообщение
Но, блин, получается, что в двух модулях можно объявить 2 глобальных переменных с одинаковыми именами?
Что за чушь? Ваши переменные объявлены как static, то есть они локальные для каждой единицы трансляции. До тех пор, пока вы static сущности будете неоправданно называть "глобальными", будет получаться вот такая "удивительная" чушь.

А про "одинаковые имена" меня вообще безмерно удивило. Для чего же по-вашему предназначен static в языке C??? static для того и предназначен, чтобы вы могли спокойно объявлять переменные и функции локальными для данной единицы трансляции, т.е. не беспокоиться о потенциальных конфликтах имен с другими единицами трансляции.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 21:34  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Для чего же по вашему предназначен static в языке C???
Ну, я всегда думал, что для указания компилятору, где выделять память под переменную - в области данных (а не на стеке или в куче).
Чо делать-то?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 21:41
Цитата Сообщение от Verevkin Посмотреть сообщение
Чо делать-то?
Вам уже сказали, что делать.

Я только до сих пор не понял, о каком языке идет речь. Форум по С++. В проекте - явно С.

Цитата Сообщение от Verevkin Посмотреть сообщение
Ну, я всегда думал, что для указания компилятору, где выделять память под переменную - в области данных (а не на стеке или в куче).
Это так только для объявлений переменных в локальных блоках.

Для внешних объявлений роль static заключается именно в управлении связыванием: внешнее или внутреннее.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 21:50  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Я только до сих пор не понял, о каком языке идет речь. Форум по С++. В проекте - явно С.
Да, пожалуй Си.
-----
extern не помог. Всё равно указатели имеют разные значения.



main.c
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
 
#include "var.h"
#include "prf.h"
 
int main()
{
    printf("addresses of statics\n");
    printf("0x%08X = 0x%08X\n", (uint32_t)&staticX, staticX);
    printf("0x%08X = 0x%08X\n", prf(), staticX);
    //printf("0x%08X = 0x%08X\n", (uint32_t)pStaticX, *pStaticX);
    //printf("0x%08X = 0x%08X\n", (uint32_t)pStaticY, *pStaticY);
    getch();
    return 0;
}
prf.c
C++
1
2
3
4
5
6
7
8
#include "prf.h"
 
extern const uint32_t* pStaticX;
 
uint32_t prf(void)
{  
    return (uint32_t)pStaticX;  // &staticX;
}
prf.h
C++
1
2
3
4
5
6
7
8
9
10
11
#ifndef PRF_H
#define PRF_H
//=======================================================
 
#include "var.h" // <----- если закомментарить - undefined reference to `pStaticX' в prf.c 
#include <stdint.h>
 
uint32_t prf(void);         
 
//=======================================================
#endif // PRF_H
var.h
C++
1
2
3
4
5
6
7
8
9
10
11
#ifndef VAR_HEADER
#define VAR_HEADER    
 
//-------------------------
#include <stdint.h>
 
static const uint32_t staticX = 0x12345678;
static const uint32_t* pStaticX = &staticX;
 
//-------------------------
#endif // VAR_HEADER
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 21:51  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Для внешних объявлений роль static заключается именно в управлении связыванием: внешнее или внутреннее.
Я не знаю, что это такое. Придётся гуглить.
0
фрилансер
 Аватар для Алексей1153
6494 / 5722 / 1133
Регистрация: 11.10.2019
Сообщений: 15,282
25.12.2019, 21:55
Verevkin, вот два варианта решения. Выбирай, что больше понравится

C++
1
2
3
4
5
6
7
#include "global_var.h"
 
int main()
{
    uint32_t v1=global_var_1;
    uint32_t v2=global_var_2_reference();
}
#include "global_var.h" - включать там, где нужно видеть переменную
Вложения
Тип файла: zip global_var.zip (435 байт, 5 просмотров)
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 22:13
Цитата Сообщение от Verevkin Посмотреть сообщение
extern не помог. Всё равно указатели имеют разные значения.
Написана какая-то чушь.

Сколько раз уже повторили: никакого static в ваших объявлениях быть не должно. И определения переменных ни в коем случае не должны располагаться в заголовочном файле. В заголовочном файле допустимы только объявления переменных.

var.h
C
1
2
3
4
5
6
7
8
9
#ifndef VAR_HEADER
#define VAR_HEADER    
 
#include <stdint.h>
 
extern const uint32_t staticX;
extern const uint32_t* pStaticX;
 
#endif // VAR_HEADER
prf.c (или любой другой файл)
C
1
2
3
4
5
6
#include "prf.h" // <- предполагая, что он включает `var.h`
 
const uint32_t staticX = 0x12345678;
const uint32_t* pStaticX = &staticX;
 
/* ... */
Вот и все. Больше нигде ничего для этих переменных объявлять/определять не нужно.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 22:21  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
И определения переменных ни в коем случае не должны располагаться в заголовочном файле.
Так у меня там переменных и не было. Только константы. Константы тоже нельзя?
Весь вопрос родился из-за того, чтоб использовать константы, определённые в одном месте программы, где угодно, просто обращаясь к ним через имя.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 22:45
Цитата Сообщение от Verevkin Посмотреть сообщение
Так у меня там переменных и не было. Только константы. Константы тоже нельзя?
"Константами" в языке С называются буквальные значения и элементы enum. Все остальное - это фактически "константные переменные". Так что - именно переменные. Формально выражаясь - объекты.

Цитата Сообщение от Verevkin Посмотреть сообщение
Весь вопрос родился из-за того, чтоб использовать константы, определённые в одном месте программы, где угодно, просто обращаясь к ним через имя.
Если бы вас интересовали лишь значения этих констант, то проблем бы не было даже с вашим исходным вариантом. Но как только вас заинтересовала уникальность адреса (!) ваших "константных переменных", ситуация сразу стала принципиально другой и на сцену вышли вопросы ODR, т.е. внешнего связывания.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 22:55  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Но как только вас заинтересовала уникальность адреса (!) ваших "константных переменных"
Мне просто было нужно, чтобы таблица разместилась в бинарнике один раз. Отсюда и уникальность адреса 0-го элемента, т.е. значение указателя. Через этот указатель нужно брать данные из таблицы. Но в проекте 100500 модулей (ах, сорри, 25 лет работы на delphi дают о себе знать), пардон, единиц компиляции, и этот проект пишу не я. Моя задача - сформировать таблицу в виде единицы компиляции так, чтобы данные из неё были доступны везде и не дублировались.

Казалось, задача тривиальная. А вот хрен.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
25.12.2019, 23:13
Цитата Сообщение от Verevkin Посмотреть сообщение
Моя задача - сформировать таблицу в виде единицы компиляции так, чтобы данные из неё были доступны везде и не дублировались.
Совершенно верно. Недопущение дублирования "тяжелого" объекта - это как раз один из вариантов ситуации, когда вас интересует уникальность адреса.

Цитата Сообщение от Verevkin Посмотреть сообщение
Казалось, задача тривиальная. А вот хрен.
Задача совершенно тривиальная и как она решается (тривиально) вам уже показали.

Вся "нетривиальность" сводится лишь к продиранию через дебри постороннего шума (#include guards и т.п.), который к этой задаче не имеет абсолютно никакого отношения и который вы сюда нагнали в огромных количествах.

Цитата Сообщение от Verevkin Посмотреть сообщение
Отсюда и уникальность адреса 0-го элемента, т.е. значение указателя.
Этот указатель вам, кстати, формально совсем не нужен. Зачем еще заводить указатель, если можно сделать доступной саму таблицу?

Добавлено через 2 минуты
Или наоборот, если вы хотите доступаться к таблице именно через отдельный указатель, то саму таблицу можно где-то "спрятать", т.е. сделать static а каком-то файле реализации, но вот указатель придется сделать глобальным именно теми методами, которые мы описали выше.
1
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 23:17  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Этот указатель вам, кстати, формально совсем не нужен.
Нужен!
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
саму таблицу можно где-то "спрятать", т.е. сделать static а каком-то файле реализации
не можно, а НУЖНО!
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
но вот указатель придется сделать глобальным именно теми методами, которые мы описали выше.
Да где? Скажи номер коммента. Не найду никак.
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
25.12.2019, 23:58  [ТС]
Задача решена, скилл прокачан.
Всем участникам спасибо.



Кому интересно - прицепляю тестовый исходник.
Вложения
Тип файла: 7z Testhfile2.7z (1.2 Кб, 5 просмотров)
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13207 / 6841 / 1823
Регистрация: 18.10.2014
Сообщений: 17,304
26.12.2019, 01:50
Цитата Сообщение от Verevkin Посмотреть сообщение
Да где? Скажи номер коммента. Не найду никак.
#31

Добавлено через 18 минут
Цитата Сообщение от Verevkin Посмотреть сообщение
Кому интересно - прицепляю тестовый исходник.
Именно это я и имел в виду. Все правильно сделано (раз уж вам так хочется иметь именно эти указатели).

Остается только вопрос о том, почему у вас сами указатели не являются константными. Вам нужно иметь возможность их изменять?
0
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
26.12.2019, 08:16  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Остается только вопрос о том, почему у вас сами указатели не являются константными. Вам нужно иметь возможность их изменять?
Да не. А чо, где-то не хватает const?

0
фрилансер
 Аватар для Алексей1153
6494 / 5722 / 1133
Регистрация: 11.10.2019
Сообщений: 15,282
26.12.2019, 08:38
Verevkin, наверное, имеется в виду константность самого объекта указателя

const uint32_t* const pTABLE=TABLE;

И я тоже не понимаю, зачем этот указатель вообще нужен. Можно таблицу сделать не static и пусть торчит себе наружу. указатель тут - лишний.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
26.12.2019, 08:38

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

Shift и чертовщина...
Доброго времени суток! Недавно купил новую клаву (Genius LuxeMate i220) через некоторое время иногда на время перестал работать левый...

Чертовщина с KWrite
Только вчера перешел с Windows на Linux (Mandriva 2009.0 Free). Не получается элементарное. Открываю текстовый редактор KWrite....

Чертовщина с foreach
Добрый день. То ли меня глючит, то ли глючит. В цикле добавляю в список экземпляр класса work_neuron, 2 поля которых предварительно...

Warning: include(1) [function.include]: failed to open stream: No such file or directory in
Выдает вот такую ошибку Warning: include(1) : failed to open stream: No such file or directory in...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Контроль уникальности строк в табличной части документа
Maks 18.06.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ПланированиеСпецтехники" с табличной частью "НаличиеОборудования", разработанного в КА2. Задача: контроль уникальности строк в. . .
Клиент
Uhbif79 18.06.2026
Здесь простой клиент для работы с сервером.
Сервер
Uhbif79 18.06.2026
Выкладываю простейший сервер.
Дефенестрация
kumehtar 18.06.2026
Узнал интересное слово. Дефенестрация. Это когда ты выбрасываешь кого-либо или что-либо из окна. Возьму на вооружение)))
Дихотомия добра и зла
kumehtar 18.06.2026
Как Дзен-буддисты говорят о добре и зле: не нужно воевать против зла, нужно воевать против невежества. Тогда добро станет ествественным, и поэтому вечным. Но дело в том, что невежество всё время. . .
Своя Интернет-Компания
iceja 18.06.2026
Я программист с экономическим образованием, пишу свой проект, это SaaS для бизнесов. Мне нужен co-founder с высшим экономическим образованием, и/ или инвестор. Сейчас проект в интенсивной разработке,. . .
24 Мат модель здравосохранения: функциональные требования к строительству пищеблока
anaschu 18.06.2026
СРесурсами1: финансовый SD-контур, калькулятор функциональных требований пищеблока Сегодня разделили затраты в агенте Экономика по образцу модели НАСОСЫ, добавили расчёт ROI и построили первый. . .
23. что сделано за последнее время.
anaschu 17.06.2026
• Эталон: Клиника НИИ питания РАМН, Москва — централизованный пищеблок, 225 коек, 180 пациентов • Git: репозиторий med2, ветка абсентеизм. Рабочий файл: СРесурсами1_v4. alp • Смежный проект:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru