April 26, 2024, 10:53:26 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Static Question

Started by J B Wood (Zumwalt), October 13, 2006, 01:50:20 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

J B Wood (Zumwalt)

Why is the keyword static ignored?
I need that variable open for the entire project but created by the NetworkServer class as a pointer.


class NetworkServer
{
declare _NetworkServer();
declare NetworkServer();
declare initServer();
declare destroyServer();

struct Packet
{
int PlayerID;
string msg;
};
int *Result;
int *UNASSIGNED_PLAYER_ID;
int Client = 0;
static int *Server;
int MyID = -1;
int *BitStream;
int ID_MOUSE_UPDATE;
};

Parker

A couple of things:
a) That structure (Packet) isn't local to the NetworkServer class; you can't do that in Aurora. It may compile, but it is available to the whole program.
b) Static for classes isn't supported yet. For now just use a global variable.
c) Not very important, but structures and classes and the like don't need a semicolon after the }.

J B Wood (Zumwalt)

Didn't make much sense to me.

The STATIC keyword is used to create a static variable in a subroutine.  A static variable does not lose it's contents between subroutine calls and acts much like a global variable.  Usage:

sub mysub(),int
{
static int count = 5;
....
}


If I move the struct outside the class I get errors for the struct.
So back to my initial problem.. static...
The varialbe needs shared as long as the server is live.
The moment the server is dead, so is the variable.
I don't think I am making sense.

Parker

QuoteIf I move the struct outside the class I get errors for the struct.
??? What errors do you get? You shouldn't get any.

QuoteSo back to my initial problem.. static...
The varialbe needs shared as long as the server is live.
The moment the server is dead, so is the variable.
I'm not quite sure what you're getting at. Static can't be used in a class context at the moment, but still it doesn't seem like what you're doing is a candidate for a static variable. I could be wrong though, since I don't really understand what the class is supposed to do.

If your whole program is only going to ever have one Server, then you should make it static. Otherwise it should be left normal. And currently you have to just make it global; there is no class static as in C++.

J B Wood (Zumwalt)

Please explain global and the pointer.
In my INC file, I tried to put:

global int *Server;


I get syntax error int.
Then I tried:

int *Server;


None of the methods inheriting from the INC understood what *Server was.
It compiled, but the classes and methods that use (Server) said that Server was undefined.

I assume that just having

int *Server;


Inside an include file somewhere, it is global.
I also assume that it has a default value of 0.
Both are probably wrong assumptions.

Now with the struct, I took the code and placed it outside the class but still a member of the include file.

struct Packet
{
int PlayerID;
string msg;
}


taking your advice on removing the ; after the }
this again gave me a syntax error, so I tried the ;, to no availe, so I moved it back into my class
*shrugs*

obviously I just don't understand the full purpose to include files since all I want is a single Server that is an integer pointer, that is available anywhere
that is where I thought it needed to be and how

When I move it out, all my class methods break that look for a Server object

J B Wood (Zumwalt)

And the saga continues... Here is my confusion in a nutshell..

typedef.inc

uint *Server;


rakknet.inc

#include "typedef.inc"


rakknet.src

NetworkServer :: initServer()
{
#break;
Server=RN_GetRakServerInterface();
OutputDebugStringA(STR$(Server));
RN_ServerInitializeSecurity(Server,0,0);
RN_ServerStart(Server,8,0,0,60069);
RN_ServerStartOccasionalPing(Server);
RN_ServerSetRelayStaticClientData(Server,1);
BitStream=RN_BitStreamCreate1(0);
ID_MOUSE_UPDATE = 100;
Result=RN_ServerIsActive(Server);
OutputDebugStringA(STR$(Result));
if(Result=1)
{
TANK tankGame;
tankGame.Game();
OutputDebugStringA("Out of Tank Game");
}
RN_ServerDisconnect(Server,0);
Result=RN_ServerIsActive(Server);
OutputDebugStringA(STR$(Result));
}



tank.src

#include "rakknet.inc"

TANK :: Game()
{

s.RenderText(8,208,"ServerID: "+NumToStr(Server),RGBA(255,255,0,255));
}


End result, ServerID: 0

But the server is running... and terminates properly when the game exits.
Any clues?

Parker

Why is Server a pointer? And what does it represent?

When we say global variable as in static, that doesn't mean it as if you'd used the GLOBAL keyword on it. It means it is not local to a subroutine or a class. However, to create a global (visible to all modules) variable, do this:
int variable;
global variable;

Hopefully there will be some better syntax for this soon (e.g., global int variable;) Do the OutputDebugString statements show anything? Because you're dealing with two different variables called Server: one in rakknet.src and one in tank.src.

I can't really help you much because you have to pay for Raknet so I don't really have access to it. However -

- Usually constants are created with the CONST or #define keywords. I would do this with ID_MOUSE_UPDATE. Also, some of these variables may not need to be inside a class. Again, I don't know since I don't have the API.

I don't know your background in OOP and I don't have that library so I can't really tell whether or not you're setting this up right. I also don't know what "Server" is supposed to be. If it's a pointer to some structure, it shouldn't be 0. But if it's an identifier (maybe an array index) used internally inside the library, the first registration should probably be 0. The real indicator is whether or not the library works.

J B Wood (Zumwalt)

This brings a new question then.
For a global variable, obviously if I place it in a single include file, this should make it available to the project, assumably.
So if I include that single include anywhere in the project 1 time, the rest of the source files should know of it, but they don't.
I did as you suggested, now the error I get is:
Duplicate public symbols Server.

If I remove the #include on 2 of the 3 locations, it still won't compile because now those 2 source files no longer know about the global Server.
Server is a pointer not an index array element.

I want to simply get a handle on the variable elsewhere in the program but the class that is running it.
I have even setup a getter and a setter which work, but, I still don't get the value in a different class, only the main class.
So now the question, backing up a few steps, is when you have 1 global variable that is in 1 include, you have 3 source files, how do they share that global variable?
If I do a #include "include.inc"  in all 3, I get the Duplicate public symbols Server.

Thanks again for hints.

Parker

Sorry, apparently I wasn't thinking. The correct way to do a global variable is:
myfile.src
int x;
global x;


myfile.inc
extern x as int;

I'm not quite sure if the EXTERN is erased when it is found defined, but it should be in my opinion, otherwise the code gets really cluttered and doesn't look good.

When I was talking about an array, I meant that it was used internally in the library; you wouldn't know if it was used as an array index.

Ionic Wind Support Team

Just for reference the STATIC keyword is only for variable defined locally in a subroutine, they won't affect a structure or class member, nor would you want them to.  You can make a instance of a structure static, or an instance of a class for that matter.  A static instance of a class would be a little odd and would not be constructed properly.

The global/extern keywords work the same way they do in IBasic Pro.  In one file you can make a file global variable visible to other objects by marking it as such:

global gl_a;
int gl_a;

And in any other source file:

extern gl_a as int;

Which tells the linker that the variable is defined in another object file. 
Ionic Wind Support Team

J B Wood (Zumwalt)

Looks like I need to create another include to hold globals.
It can't be a member of an include that gets included for other purposes or I get the duplicate error.
I have to use extern for my purposes.

Also, FYI, Raknet is usable without purchase for freeware products. IF you plan on selling anything that uses it, that is when you have to purchase it. I own the enterprise license, so it doesn't bother me either way. I am using version 2.482 for this, since my wrapper is based on that version. Its a little deeper than that though. The wrapper I have is what speaks to the API, so it exposes the methods in a way I can use them. The DLL's that come with raknet can't be used directly by Aurora (atleast no way I have found), so you have to expose the methods then use that exposed method.

Anyway, the entire purpose to this exercise is for me to pass the active server pointer ID into other classes, as long as the server is live, this will give me the ability to start a second monitor thread within the game itself. The server starts on its own thread. So I have an application thread, a server thread, and a game thread. The application thread is the parent to everything, the game thread live or not, does nothing to the server thread, but I would like to see the server ID while in the game thread.

J B Wood (Zumwalt)

October 14, 2006, 08:54:31 AM #11 Last Edit: October 14, 2006, 08:57:17 AM by zumwalt
Ok this was not as obvious and simple as it first appeared. So only read on if you are a simpleton like me.
If you are a master, just skip this post.

Globals as defined in Aurora for the sake of sanity in my mind, need to have thier own INC file.
You place anything in that INC that is going to be a global, here is why.
You have a variable, in my case, a pointer named Server, that you want the rest of your code to see.
Well, you need to avoid duplicate declaration errors, and undefined variable errors and the like but still have the single pointer / value available to be read /modified anywhere.

Here is the switcheroo. You only include the global INC ONCE, no more than the one time, anywhere. Once it is included, you simply do something like an extern to tell that section of the code which global variable you want to use. You place that same extern line in every source file that is going to use that shared global variable.
The only catch is, you don't need extern in the first source file you have included the global include file in.

I realize people are reading this and going, man that is so obvious, why on earth did you bother to post it?
We come to the initial teaching in Aurora that if you want to use something in an include definition file, you have to #include it in every source that will use stuff in it.
Thats all fine and dandy for non global items, but if you place just 1 global item in the include you can no longer include that file in every source where you need the other items, you have to literally use extern at that point.

This is my experience only and is subject to change based on buda teaching.
As always Mr Lobster "GET IN MY BELLY"

Ionic Wind Support Team

Or just use the preprocessor.

#ifndef GLOBALS_DEFINED
#define GLOBALS_DEFINED
  global glint;
  int glint;
#else
  extern glint as int;
#endif

Ionic Wind Support Team

J B Wood (Zumwalt)

How would I use this?
I place it obviously in my include file.
Then I tried to just include it in my source.
I simply get the same problem I had before as "Duplicate Pulic symbols Server"

Ionic Wind Support Team

Actually it would probably be better to use it this way:

//globals.inc
#ifdef DEFINE_GLOBALS
  global glint;
  int glint;
#else
  extern glint as int;
#endif

Then in your main source file have a

#define DEFINE_GLOBALS
#include "globals.inc"

And every other source file have just

#include "globals.inc"

It's just a suggestion as I don't code that way, but you seem to want to have variables defined in an include file. 
Ionic Wind Support Team

J B Wood (Zumwalt)

October 15, 2006, 09:43:10 AM #15 Last Edit: October 15, 2006, 09:50:30 AM by zumwalt
It doesn't have to be in an include file, it can be in a source file, as long as the rest of the source files know of its existance.
You had stated before, put all of my definitions in include files, to me a global variable is a definition.
I tried also to put it only in a single source file, and that source file is included in the project.
However, nothing else sawÂÃ,  the variable, and I don't want to do an #include "source.src" anywhere.
So how do I place it in a source file, and yet it be totally global that all of the other source files know of its existance?

I placed this code:

#ifndef GLOBALS_DEFINED
#define GLOBALS_DEFINED
  global glint;
  int glint;
#else
  extern glint as int;
#endif


In my main src (first source file of the project), however, if I don't do:
extern glint as int;

In the other source files, they don't know about glint.
Maybe this is a bug based on how you are describing it should work.

J B Wood (Zumwalt)

Nevermind. I decided to do the long way around on it. Its no longer declared as global.
I can get the variable the way I am doing it now, just thought it would be easire to follow if it was global.

What I do now, is that in my raknet source file I simply have

pointer Server;


Then I use a getter and a setter for it:

NetworkServer :: GetServerID(),pointer
{
return Server;
}

NetworkServer :: SetServerID(pointer p)
{
Server=p;
}


So now in my other source files I simply add:

#include "raknet.inc"


Somewhere around the top of the code block that I want to get the values in the Server varialbe all I now do is:

NetworkServer currentServer;


Then I can use the getter or setter.
In my game loop I have:

s.RenderText(8,208,"ServerID: "+STR$(currentServer.GetServerID()),RGBA(255,255,0,255));


The only thing about this that bugs me, is now I am creating an instance of the class every time I want to get the value of Server, and I am assuming that Server is now private in the source file since I am not declaring it as global.


Ionic Wind Support Team

October 15, 2006, 12:08:33 PM #17 Last Edit: October 15, 2006, 12:10:32 PM by Paul Turley
You didn't see my second example.  After thinking about it the first one wouldn't have worked, which is why I provided another method ;)

Variables are not definitions, they create a physical entity in the executable.  So if you have them in an include file you are creating duplicate physical entities once the file is included more than once.  The second method of using the preoprocessor I gave would have worked in this case since your only creating the variable once and extern'ing it for every other source file.

As I mentioned I don't code that way.  For OOP languages you should have a master "app" class and anything that is shared between source files gets a pointer to that instance of that app.  So you have an app class in your main source file, and a pointer to that app class, with an accessing function:


//FILE: defs.inc

Class MyApp
{
       declare Run();
       declare GetServer(),INT;
private:
       int m_nServer;
       CWindow mainWnd;
}


//FILE: main.src
MyApp::GetServer(),int
{
     return m_nServer;
}

//global app pointer
MyApp *gl_TheApp;

//global accessing funciton
global sub GetMyApp(), MyApp *
{
return gl_theApp;
}

sub main()
{
    //create the app and run
    gl_TheApp = new(MyApp,1);
    gl_TheApp->Run();
    delete gl_TheApp;
    gl_TheApp = NULL;
}


Then in any source file you have complete access to the app instance with one external declare


//FILE somefile.src
#include "defs.inc"
declare extern GetMyApp(), MyApp *;

sub SomeFunction()
{
      if(GetMyApp()->GetServer() == 0)
      {
      }
}



Again this is just an example.  The "Run" method of the app class would be where your code really starts.  I find that coding OOP applications this way solves a lot of problems.  Anything you would have made "Global" in a procedural application can be put in the App class and then it is available from anywhere without having to worry about linkage, or cyclical includes, or what have you.

The other benefit is the App class can use a destructor method to do cleanup, which happens automatically when the class is deleted.

Paul.
Ionic Wind Support Team

J B Wood (Zumwalt)

Thank you Paul, I will comb over this and my code to see how I will impliment the change. I really need a solid clean up process for what I am physically doing at this point in the game. This information should help me alot.

Haim

I am trying to understand the coode of the last example and I have two (probably stupid) questions:
1. Why use a global sub to return a pointer that is already globally accessible?
2. Why assign Null to the pointer after it has been deleted?

Haim


Ionic Wind Support Team

October 15, 2006, 11:48:53 PM #20 Last Edit: October 15, 2006, 11:50:37 PM by Paul Turley
The variable could be globally accessable to all source files by using the 'global' keyword.  As written it is a file global variable.  The function serves as a base and could be modified to do sanity checks, debugging, etc. Which can serve to track down hard to find errors:


global sub GetMyApp(), MyApp *
{
#ifdef DEBUG
   if( gl_TheApp == NULL )
   {
       MessageBox(NULL,"App class access while null", "Error");
       #break
   }
#endif     
return gl_theApp;
}


So if you're in debug mode and the app pointer hasn't been allocated yet you can follow the call stack to see where the error originated.

As a habit I always set pointers to NULL after a delete.  Accessing a NULL pointer causes an exception which can easily be followed back in a debug build.  If you didn't set it to NULL the data may still be visible if the system hasn't reallocated that block yet.  And after many years of dealing with access violations it has become second nature to do.  Just good practice ;)

In this particular instance it probably isn't necessary.  I can, however,  imagine a scenario where a message was sent and then the app exits before that message is processed.  If your handler for that message uses the GetMyApp function you could have one of those hard to track down crashes on exit.  Which I am sure many have run into before.

Paul.
Ionic Wind Support Team

Haim

Thanks for the swift response and explanations.

Haim


Ionic Wind Support Team

You're welcome.

Once you get the hang of using an app class it does make life easier for larger programs.  If you're only making a small utility or a single source file program then it really isn't necessary.
Ionic Wind Support Team

J B Wood (Zumwalt)

I attempted a few itterations of this over the weekend, although I didn't encounter any errors, I had the end result of multiple pointers getting generated. Very hard to explain and I rolled back the code to what I had that was working. I figured what I am going to do is start a fresh new project and play around with this some more before trying to fit it into the project I already have created.

Its a very good idea that Paul has come up with for the class pointer and I will hopefully get the hang on how to use it in Aurora soon enough. I still have around 100 methods in my current project to test but once they are done, the end result will justify the means.

Thanks again for this help Paul.