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

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

14.02.2012, 21:44. Показов 9306. Ответов 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 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути
Programma_Boinc 01.01.2026
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути Сочетание глобально распределённой вычислительной мощности и инновационных. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru