Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 03.02.2010, 12:14   #1
Кипящий чайник
Форумчанин
 
Регистрация: 17.12.2009
Сообщений: 101
По умолчанию Потерявшаяся переменная

Теперь, когда с массивами и кодировками всё ясно, всплывает ещё одна подводная мина.
Поскольку я хочу реализовать в текстовом квесте функцию, которая будет рисовать условную карту, чтобы облегчить жизнь игроку, то пришлось ввести систему коориднат. Пока координата одна, y, чтобы жизнь была легче.
Все функции я храню в fns.h, объявил её ещё даже до прототипов функции. В fns.h есть три функции зависящие от переменной y:

Analysis - функция анализа команд. Тут вызывается функция GoTo, которая ориентируется на y.
GoTo - проверяет значение y, а затем увеличивает или уменьшает значение координаты, таким образом игрок как бы перемещается по миру.
DrawMap - она проверяет значение y и в соответсвии с ней выводит на экран карту с положением игрока.

Все функции рабочие и проверенные. Однако я, видимо, совершил ошибку, сделав их все зависимыми от y.
Дело в том, что y я храню в том же fns.h, и она, по идее, должна быть глобальной переменной.
Однако DrawMap при запуске игры не отрисовывает карту. Я поместил в функцию эту же координату и скомпилировал в отдельном модуле. Всё работает.
Однако в модуле fns.h DrawMap как будто не видит y. Я ввёл указатель на y, сразу после y. Этот указатель присутствует в теле функции DrawMap, но она всё равно как будто не видит эту переменную. Как же организовать так, чтобы ВСЕ три функции (или больше, если понадобится) таки НАШЛИ эту переменную?

Последний раз редактировалось Кипящий чайник; 03.02.2010 в 15:21.
Кипящий чайник вне форума Ответить с цитированием
Старый 03.02.2010, 13:42   #2
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Три варианта:
1) Передавать у в качестве параметра в функции
2) Если используется ООП, то класс игрока реализовать по паттерну singleton и из него уже брать у
3) Сделать у глобальной переменной и соответствующий модуль подключать во всех нужных местах (Только не нужно у совать в *.h файл, а то будет куча переменных. В хедере переменная должна быть описана как extern, а уже в .срр нужно её описывать "нормально")
pu4koff вне форума Ответить с цитированием
Старый 03.02.2010, 15:18   #3
Кипящий чайник
Форумчанин
 
Регистрация: 17.12.2009
Сообщений: 101
По умолчанию

Первый вариант, боюсь, не пройдёт, ибо DrawMap, во-первых, и так использует указатель на y в качестве параметра. Но ей это не помогает.
Второй вариант, увы, тоже не, уж простите за каламбур, не вариант. Хотя и используется ООП, но используется только для команд и каки-либо объектов, но игрока в них нет, по причине ненадобности. Хотя можно поэксперементировать. Звучит действительно, как решение проблемы.
Третий вариант очень мне интересен. Как в данном случае, описать её как extern? Просто extern int y?
Кипящий чайник вне форума Ответить с цитированием
Старый 03.02.2010, 16:37   #4
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Цитата:
Сообщение от Кипящий чайник Посмотреть сообщение
Как в данном случае, описать её как extern? Просто extern int y?
Если я еще не совсем забыл С++, то как-то так должно быть:
Код:
// my_header.h

extern int y;

// my_source.cpp
#include "my_header.h"

int y;

// Модуль с реализацией функций
#include "my_header.h"

// Тут  должна уже быть видна глобальная переменная y

void Analysis(...)
{
  ...
}
pu4koff вне форума Ответить с цитированием
Старый 10.07.2011, 18:15   #5
malor
Форумчанин
 
Регистрация: 23.05.2007
Сообщений: 151
Вопрос Объявление глобальной переменной в хедере

Что-то странное с глобальной переменной:
Код:
myheader.h
extern HANDLE hSyncFile;
...............


file1.cpp
#include "myheader.h"
HANDLE hSyncFile;
...............


file2.cpp
#include "myheader.h"
HANDLE hSyncFile;
...............
Компилятор выдает:
error LNK2005: "void * hSyncFile" (?hSyncFile@@3PAXA) already defined in file2.obj
Почему?
malor вне форума Ответить с цитированием
Старый 10.07.2011, 20:55   #6
Сыроежка
Форумчанин
 
Регистрация: 01.07.2011
Сообщений: 423
По умолчанию

Цитата:
Сообщение от malor Посмотреть сообщение
Что-то странное с глобальной переменной:
Код:
myheader.h
extern HANDLE hSyncFile;
...............


file1.cpp
#include "myheader.h"
HANDLE hSyncFile;
...............


file2.cpp
#include "myheader.h"
HANDLE hSyncFile;
...............
Компилятор выдает:
error LNK2005: "void * hSyncFile" (?hSyncFile@@3PAXA) already defined in file2.obj
Почему?
Значит у вас два определения одной и той же функции! Где вы определяете функцию? В заголовочном файле? ТОгда у вас каждая единица трансляции file1 и file2 содержат определение одной и той же функции.
Со мной можно встретиться на www.clipper.borda.ru
Сыроежка вне форума Ответить с цитированием
Старый 10.07.2011, 20:59   #7
Сыроежка
Форумчанин
 
Регистрация: 01.07.2011
Сообщений: 423
По умолчанию

Цитата:
Сообщение от Кипящий чайник Посмотреть сообщение
Теперь, когда с массивами и кодировками всё ясно, всплывает ещё одна подводная мина.
Поскольку я хочу реализовать в текстовом квесте функцию, которая будет рисовать условную карту, чтобы облегчить жизнь игроку, то пришлось ввести систему коориднат. Пока координата одна, y, чтобы жизнь была легче.
Все функции я храню в fns.h, объявил её ещё даже до прототипов функции. В fns.h есть три функции зависящие от переменной y:

Analysis - функция анализа команд. Тут вызывается функция GoTo, которая ориентируется на y.
GoTo - проверяет значение y, а затем увеличивает или уменьшает значение координаты, таким образом игрок как бы перемещается по миру.
DrawMap - она проверяет значение y и в соответсвии с ней выводит на экран карту с положением игрока.

Все функции рабочие и проверенные. Однако я, видимо, совершил ошибку, сделав их все зависимыми от y.
Дело в том, что y я храню в том же fns.h, и она, по идее, должна быть глобальной переменной.
Однако DrawMap при запуске игры не отрисовывает карту. Я поместил в функцию эту же координату и скомпилировал в отдельном модуле. Всё работает.
Однако в модуле fns.h DrawMap как будто не видит y. Я ввёл указатель на y, сразу после y. Этот указатель присутствует в теле функции DrawMap, но она всё равно как будто не видит эту переменную. Как же организовать так, чтобы ВСЕ три функции (или больше, если понадобится) таки НАШЛИ эту переменную?
Вопрос в том, во сколько модулей вы включаете свой заголовок fns.h. Скорей всего при компиляции и редактировании создается несколько экземпляров этой переменной, которые не зависят друг от друга.
Со мной можно встретиться на www.clipper.borda.ru
Сыроежка вне форума Ответить с цитированием
Старый 10.07.2011, 23:20   #8
malor
Форумчанин
 
Регистрация: 23.05.2007
Сообщений: 151
Вопрос hSyncFile - это переменная.

Но у меня нет функций с именем hSyncFile! Откуда компилятор так решил?

"Чтобы понять, почему это так важно, необходимо различать объявление (declaration) и определение (definition). В объявлении указывается имя и тип объекта. В программе может быть несколько объявлений одного и того же объекта, но только одно определение."
(Герберт Шилдт, "Полный справочник по С++", 2007 г., стр.49 )

"Спецификатор extern играет большую роль в программах, состоящих из многих файлов. В языке С/C++ программа может быть записана в нескольких файлах, которые компилируются раздельно, а затем компонуются в одно целое. В этом случае необходимо как-то сообщить всем файлам о глобальных переменных программы. Самый лучший (и наиболее переносимый) способ сделать это — определить (описать) все глобальные переменные в одном файле и объявить их со спецификатором extern в остальных файлах.
На практике программисты обычно включают объявления extern в заголовочные файлы, которые просто подключаются к каждому файлу исходного текста программы. Это более легкий путь, который к тому же приводит к меньшему количеству ошибок, чем повторение этих объявлений вручную в каждом файле."

(Герберт Шилдт, "Полный справочник по С++", 2007 г., стр. 50-51 )
malor вне форума Ответить с цитированием
Старый 10.07.2011, 23:48   #9
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Цитата:
Компилятор выдает:
error LNK2005: "void * hSyncFile" (?hSyncFile@@3PAXA) already defined in file2.obj
Почему?
Объявление без extern должно быть строго в одном месте (ODR - One Definition Rule, правило одного определения).
Объявив переменную в хидере как extern, вы тем самым дали понять всем cpp файлам, включающим его, что где-то эта переменная определена. Компилятор остается довольным, и во всех этих файлах работает с переменной как с объявленной. Но несмотря на extern-объявление, переменная все же должна быть где-то объявлена без extern, причем ровно один раз во всем проекте. И вот за этим уже следит линковщик - единожды определенную переменную он связывает со всеми местами, где она используется.
Говоря по-простому, в списке сотрудников нашей организации (файл Employees.h) значится некий Вася Пупкин
Код:
extern Employee VasyaPupkin;
В принципе все имеют доступ к этому списку, и потому начальник, зная о его существовании, может отправить Васю Пупкина грузить чугуний
Код:
VasyaPupkin.WorkHard();
бухгалтерия может начислять ему зарплату
Код:
VasyaPupkin.GiveTugrics(10);
а секретарша Леночка может писать ему любовные письма
Код:
SweetLena.WriteChmoki(&VasyaPupkin);
И неважно, что вживую никто из них его в жизни не видел. Бюрократический аппарат (Linker) обеспечивает связь между всеми сотрудниками по мере необходимости.
Но тут есть один нюанс. Несмотря на то, что Вася значится в списке сотрудников, он все-таки должен физически находиться в стенах этой организации, или хотя бы батрачить дома через удаленный доступ
Код:
//Room404.cpp
#include "Employees.h"

Employee VasyaPupkin;
Товарищи Васи, тоже сидящие в комнате 404, видят его воочию, и тоже могут всячески над ним изгаляться, например, подложить кнопку ему на стул
Код:
DoFunny(VasyaPupkin);
или угостить печеньками
Код:
VasyaPupkin.InviteToDarkSide();
Им даже не надо знать, что Вася проходит по каким-то там спискам. Хотя вообще-то они знают, но им от этого ни холодно ни жарко. А вот всем остальным приходится пользоваться списком, но благодаря тому, что доблестная бюрократия работает как надо, производственный процесс идет как положено, и Васю прилежно эксплуатируют.
Однако, из-за различных неприятных ситуаций могут возникнуть ба-а-альшие проблемы.
Например, в кабинет 501 забыли выдать списки сотрудников, и бедные работяги сидят там как на необитаемом острове, знать не зная, что в мире есть кто-то еще ("Вася? Какой Вася?")
Код:
//Room501.h
//Not included "Employees.h"

VasyaPupkin.Howdy();   //Error: undefined symbol VasyaPupkin
Вася мог вообще тут никогда не работать, или поссориться с начальником, после чего Васю никто не видел:
Код:
//Room404.cpp
#include "Employees.h"

//Employee VasyaPupkin;

//SecurityRoom.cpp
#include "Employees.h"

SpyAfterEmployee(&VasyaPupkin);   //Linker Error: Unresolved external VasyaPupkin
А еще в организации может быть два Васи Пупкина. Может быть, это два близнеца, разлученных в детстве, а может просто они произошли в далекие времена от одноклеточной бактерии с этой фамилией, пусть даже их эволюционное развитие пошли разными путями. Непорядок может случиться даже если они сидят в одной комнате, но об этом нам сразу скажет старший по комнате (Compiler)
Код:
//Room404.cpp
Employee VasyaPupkin;
Employee VasyaPupkin;
Но может случиться так, что они сидят по разным комнатам, в ведомостях числится только имя, и никто их обоих одновременно не видел. Однако как только бюрократия начнет работать на полную катушку, сразу же возникнет вопрос: "Ну и кто из них пиццу заказывал?"
Код:
//Room404.cpp
#include "Employees.h"

Employee VasyaPupkin;

//Room403.cpp
#include "Employees.h"

Employee VasyaPupkin;

//Hall.cpp
Courier.HereIsTwoPizzas(&VasyaPupkin);

//Linker error VasyaPupkin already defined
Мораль: в вашей организации (проекте) сколько угодно раз может быть написано, что тут работает и отдает лучшие годы своей жизни Вася Пупкин (extern Employee VasyaPupkin; ), но настоящий Вася Пупкин должен быть только один (Employee VasyaPupkin; ). В крайнем случае - несколько, но так, чтобы это осталось между нами (области видимости не пересекались).
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 11.07.2011, 00:11   #10
coNsept
Форумчанин
 
Аватар для coNsept
 
Регистрация: 14.12.2009
Сообщений: 716
По умолчанию

У Грома походу хорошее настроение :D
coNsept вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Переменная и Memo ben95 Общие вопросы Delphi 2 18.04.2009 12:10
c# ссылочная переменная hizahazahub Общие вопросы .NET 1 16.04.2009 20:53
Странная переменная. GreenDan Помощь студентам 6 25.08.2008 19:35
Динамическая переменная kezman Общие вопросы C/C++ 1 29.07.2008 13:49