С Новым годом! Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.70/43: Рейтинг темы: голосов - 43, средняя оценка - 4.70
60 / 57 / 8
Регистрация: 22.07.2011
Сообщений: 436

Заголовочные файлы

14.02.2012, 21:44. Показов 9309. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Собственно проблема состоит вот в чём: у меня 2 формы. В каждой подключен файл, в котором объявлена глобальная переменная типа HANDLE. При нажатии кнопки (кнопка находится на первой форме) находится нужный процесс и его хэндл записывается в переменную. Почему я могу без проблем использовать эту переменную в первой форме, но вторая форма видит эту переменную как 0?
Также при компиляции есть предупреждение: [Linker warning] Public symbol '_ProcessHandle' defined in both module... Как от него избавиться?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
14.02.2012, 21:44
Ответы с готовыми решениями:

Обращение между формами. Заголовочные файлы подключил. Пытаюсь из трэк бара внести значение в Лейбл на другой форме
void __fastcall TGame_Form::TrackBar1Change(TObject *Sender) { Form_Inform->Label2->Caption=IntToStr(Game_Form->TrackBar1->Position); ...

Не подключаются стандартные заголовочные файлы
Установил Visual Studio 2019. Сильно в процесс установки не вникал (может, что не установилось?) //#define CF #include...

Заголовочные файлы .h, файлы исходного когда c/c++ и установление связи между ними
Всем добрый вечер!) Относительно недавно стал изучать c/c++, хочу полюбопытствовать ,так как появился вопрос. Почему при объявлении...

10
 Аватар для cpp_developer
20124 / 5691 / 417
Регистрация: 09.04.2010
Сообщений: 22,546
Записей в блоге: 1
14.02.2012, 21:57
Объявить переменную в одном модуле как
C++
1
extern tip_peremennoy VashaPeremennaya;
, и компиль все правильно глаголит.
0
60 / 57 / 8
Регистрация: 22.07.2011
Сообщений: 436
14.02.2012, 22:40  [ТС]
Я так понял, что нужно объявлять в cpp. Объявил, но вторая форма же не видит этой переменной.
0
 Аватар для cpp_developer
20124 / 5691 / 417
Регистрация: 09.04.2010
Сообщений: 22,546
Записей в блоге: 1
14.02.2012, 23:19
объявить в заголовочном файле, и включить этот заголовочный файл в файл срр второй формы.
1
60 / 57 / 8
Регистрация: 22.07.2011
Сообщений: 436
14.02.2012, 23:22  [ТС]
[Linker error] Unresolved external '_ProcessHandle' referenced from...
0
 Аватар для cpp_developer
20124 / 5691 / 417
Регистрация: 09.04.2010
Сообщений: 22,546
Записей в блоге: 1
14.02.2012, 23:46
Лучший ответ Сообщение было отмечено как решение

Решение

Межмодульное взаимодействие
Как указано в стандарте (см. п.п. 3.2/1 в [1]), единица трансляции не должна содержать более одного определения любой переменной, функции, класса, перечисления и шаблона (в каждой области видимости, естественно). Это — так называемое правило одного определения (One-Definition Rule, ODR). В первую очередь это правило касается определений классов, переменных и функций. Для переменной компилятор по ее определению вычисляет размер и резервирует место в памяти, поэтому при наличии более одного определения в одной области видимости у него «возникают проблемы». Для класса компилятор тоже вычисляет размер, хотя обычно и не резервирует место в памяти — это делается при объявлении объектов класса.

ПРИМЕЧАНИЕ
Для статических полей класса память резервируется до первого объявления объекта класса — при определении статического поля.

Для функции компилятор генерирует код, который, в конечном счете, тоже займет свое место в памяти.

А вот объявлений может быть несколько. Объявление лишь добавляет некоторое имя в данную область видимости и обычно используется для согласования типов. Однако при разделении программы на отдельные модули возникают вопросы о взаимодействии определений и объявлений, прописанных в разных модулях. Естественно, речь не идет о локальных объектах — с ними все ясно.

Межмодульные переменные и функции

Начнем с простых переменных. Допустим, у нас есть два модуля A.cpp и B.cpp. В модуле A определена целая переменная i вне всех классов и функций:
C++
1
int i = 2;
Такая переменная называется глобальной. В файле A она видна от точки определения и до конца файла. Однако в модуле B эта переменная не видна. И если вдруг нам потребуется в модуле B присвоить ей другое значение, у нас возникнут некоторые проблемы. Нельзя просто написать:
C++
1
i = 1;
В этом случае компилятор при обработке модуля B «не видит» модуль A и ничего не знает об определенной там переменной, поэтому мы получим сообщение о неопределенной переменной. Также нельзя написать:
C++
1
int i = 1;
Такая запись является повторным определением. Компилятор-то «возражать» не станет — он транслирует модули по отдельности, а вот компоновщик будет «воротить нос» и сообщит, что одна и та же переменная определена дважды. Для таких случаев в С++ включено специальное ключевое слово extern. В модуле B надо объявить переменную следующим образом:
C++
1
extern int i;
После этого можно использовать переменную i в файле B любым разрешенным способом. Например, присвоить новое значение:
C++
1
i = 1;
Однако попытка совместить объявление с присвоением значения является ошибкой:
C++
1
extern int i = 1;
Такая запись служит определением, поэтому мы опять получим от компоновщика сообщение о повторном определении.

ПРИМЕЧАНИЕ

Хотя ключевое слово extern в стандарте определено как один из четырех классов хранения, проще понимать его как обозначение «внешнего» имени для данного модуля. Имя называется внешним по отношению к модулю, если объект с этим именем не определен в данном модуле.

Аналогичная картина наблюдается и с функциями. Определение функции включает тело, а объявлением является прототип. Пусть в модуле A определена функция:
C++
1
2
void f(void) 
{ cout << "f()" << endl; }
Для того чтобы эту функцию можно было использовать в модуле B, нужно объявить там ее прототип:
C++
1
void f(void);
Слова extern писать не требуется, хотя и не запрещается. Следующие прототипы эквивалентны:
C++
1
2
void f(void);
extern void f(void);
Локализация имен в модуле

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

Однако иногда бывает нужно, чтобы глобальная переменная или функция были видны только в том файле, где определены. Это позволяет сделать атрибут static, например:
C++
1
2
static int a = 1;
static void f(void) { ... }
Для определенных таким образом имен применяется внутренняя компоновка (internal linkage) — они являются локальными в модуле, где определены. Таким образом, можно говорить, что глобальные имена обладают свойством внешней или внутренней компоновки.

Разберемся с некоторыми подробностями на примере функций. Пусть у нас есть, как обычно, два модуля A.cpp и B.cpp:
C++
1
2
3
4
5
6
//--модуль A.cpp
void f1(void) {...};            // определение глобальной функции
static void f2(void){...};      // определение локальной функции
//--модуль B.cpp
f1();                           // вызов глобальной функции
f2();                           // ОШИБКА!! -- вызов невидимой функции
Функция f2() не видна в модуле B, поэтому ее вызов ведет к ошибке трансляции.

Имя функции с атрибутом static должно быть уникальным в данном модуле, но может повторяться в других модулях. Более того, локальная в модуле функция (с атрибутом static) перекрывает глобальную функцию в пределах модуля (аналогично тому, как локальная переменная в теле функции перекрывает глобальную). Например, в следующем примере функция f1() в модуле B.cpp перекрывает глобальную функцию, определенную в модуле A.cpp.
C++
1
2
3
4
5
6
7
//--модуль A.cpp
void f1(void) {...};            // определение глобальной функции
static void f2(void){...};      // определение локальной функции
f1();                           // вызов глобальной функции
//--модуль B.cpp
static void f1(void) {...};     // определение локальной функции
f1();                           // вызов локальной функции
Все то же самое относится и к глобальным переменным с атрибутом static.

Атрибут static в данном случае похож на модификатор доступа private, работающий на уровне файла. Налицо два совершенно разных смысла одного ключевого слова: с одной стороны, для локальных переменных static означает класс хранения (в статической памяти); с другой стороны, на уровне модуля атрибут static имеет смысл ограничителя видимости имен. Последнее объявлено устаревшим, поэтому применение атрибута static в таком значении является нежелательным (см. п. D2 в [1]). Вместо этого для решения проблем локализации в С++ включили пространства имен, которые мы рассмотрим далее.

Константы по умолчанию компонуются внутренним образом. Это означает, что при объявлении константы нет необходимости указывать атрибут static, чтобы сделать ее локальной в модуле. Поэтому в разных модулях можно объявлять глобальные константы с одинаковыми именами — конфликта при компоновке не происходит. Более того, чтобы сделать константу, объявленную в одном модуле, видимой в другом, нужно использовать слово extern:
C++
1
2
3
4
// модуль A.cpp
extern const int a = 2;
// модуль B.cpp
extern const int a;
Тогда компоновщик будет считать, что в модулях A.cpp и B.cpp используется одна и та же целая константа с именем a. Если мы пропустим слово extern в объявлении константы в модуле А.cpp, то получим локализованную константу, и при обработке объявления в модуле В.cpp компоновщик выдаст сообщение о неопределенном имени.

Внутренняя компоновка констант оказывает «медвежью услугу» в шаблонах. Поскольку строковые литералы — это объекты со свойством внутренней компоновки, использовать их в качестве аргумента шаблона не разрешается:
C++
1
2
3
4
5
6
7
8
template<char const *str>
class Template { ... };
Template<"literal"> T;            // Ошибка! 
Нельзя использовать и глобальный указатель:
template<char const *str>
class Template { ... };
char const *s = "Literal";
Template<s> T;                    // Ошибка!
Однако глобальный символьный массив использовать можно:
C++
1
2
3
4
template<char const *str>
class Template { ... };
char const s[] = "Literal";
Template<s> T;                    // Ошибки нет!
Для функций, объявленных как подставляемые (с ключевым словом inline), по умолчанию тоже применяется внутренняя компоновка. Функция, определенная в одном модуле, не видна в другом модуле. Даже если определения в модулях абсолютно синтаксически совпадают — это все-таки могут быть разные функции, например:
C++
1
2
3
4
5
6
7
8
// модуль A.cpp
const int a = 7;
inline void f(void) 
{ cout << a << "f()\n"; }
// модуль B.cpp
const int a = 10;
inline void f(void) 
{ cout << a << "f()\n"; }
При вызове первой функции в модуле А получим на экране 7f(), а при вызове второй в модуле В на экране появится 10f().

Так же как и определение класса, определение подставляемой функции может быть включено в программу несколько раз — по одному определению в каждом модуле. Чтобы гарантированно иметь в разных модулях одно и то же определение, мы вынесем его в отдельный модуль и подключим этот модуль в нужных файлах с помощью директивы #include — компоновщик против не будет. Естественно, определение не должно зависеть от локализованных имен, как в приведенном ранее примере.

Можно сделать подставляемую функцию глобальной — точно так же, как и константу, указав в определении ключевое слово extern:
C++
1
2
3
4
// модуль A.cpp
// Определение глобальной inline-функции
extern inline void f(void) 
{ cout << a << "f()\n"; }
В другом модуле достаточно указать прототип:
C++
1
2
3
// модуль B.cpp
// объявление внешней inline-функции
void f(void);
К прототипу можно добавить спецификаторы extern и inline:
C++
1
extern inline void f(void);
Как видите, в этом случае можно обойтись без подключения модуля с определением.

[1] — это стандарт С++
12
Диссидент
Эксперт C
 Аватар для Байт
27714 / 17332 / 3810
Регистрация: 24.12.2010
Сообщений: 38,978
15.02.2012, 13:18
SDmaN, Я поступаю так
xxx.h
C
1
2
3
4
5
6
#if  defined E
#define EX
#else
#define EX extern
#endif
  EX int yyyyy; // присваивание значения здесь не допустимо
В ОДНОМ из модулей проекта говорю перед включением #include "xxx.h"
C
1
#define E
а в других не говорю
И все конфликты разрешены
2
Модератор
 Аватар для vxg
3407 / 2178 / 354
Регистрация: 13.01.2012
Сообщений: 8,448
15.02.2012, 13:33
2 байт - просто что бы не писать два раза строчку в цпп и х файлах?
0
60 / 57 / 8
Регистрация: 22.07.2011
Сообщений: 436
15.02.2012, 20:24  [ТС]
Вобщем сделал так: нужную переменную объявил в cpp первой формы и во всех остальных модулях сделал extern. Всем спасибо.
1
Диссидент
Эксперт C
 Аватар для Байт
27714 / 17332 / 3810
Регистрация: 24.12.2010
Сообщений: 38,978
15.02.2012, 22:55
Цитата Сообщение от SDmaN Посмотреть сообщение
Вобщем сделал так: нужную переменную объявил в cpp первой формы и во всех остальных модулях сделал extern.
Все это правильно, и я так часто поступаю, да и многие, я думаю. Но если эти глобальные переменные "плывут", те. сегодня они int, завтра float, послезавтра - double, а потом и вовсе некая структура или , не дай Бог, класс, вот тут предложенный мной прием будет вполне уместен.
0
Модератор
 Аватар для vxg
3407 / 2178 / 354
Регистрация: 13.01.2012
Сообщений: 8,448
16.02.2012, 09:40
2 байт - не знаю все таки зачем ты это делаешь. обычно в h пишут например
C++
1
extern float xxx;
в cpp соответствующем этому h пишут
C++
1
float xxx = 123;
а везде где нужен доступ к xxx пишут
C++
1
#include "xxx_h_file.h"
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.02.2012, 09:40
Помогаю со студенческими работами здесь

Работа в Visual Studio 2015 - как добавить файлы исходного кода и заголовочные файлы?
Приветствую всех! Столкнулся с тем, что решая задачи по книге Лафоре про графику, не смог добавить файлы .h и .cpp, скачав их с одной из...

Заголовочные файлы
Подскажите, во время компоновки, в итоге, &quot;присоединяются&quot; к экзешнику все функции/объекты и тдп. которые указаны в заголовочном файле, или...

Заголовочные файлы
у меня есть проект такого вида Project ├── bin ├── doc ├── include │ ├── cRand │ ├── fft │ └── rs ...

Заголовочные файлы (.h)
Доброго времени суток господа! Озадачился вопросом по поводу заголовочных файлов. Но подробного, или понятного мне ответа так и не нашёл....

заголовочные файлы
Здравствуйте, хотел поупражняться с заголовочными файлами, но столкнулся с ... код целиком работает прекрасно #include...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и источниками (напряжения, ЭДС и тока). Найти токи и напряжения во всех элементах. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru