Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - C Programming Confusion

Reply to topic
Author Message
Chris
  • Guest
Reply with quote
C Programming Confusion
Post Posted: Thu Oct 28, 1999 5:27 am
This is bizzare. I wrote some test code to my emulator in C and the weirdest thing happend, which
makes no sense to me. In my program, in my main function, I declared a structure called Z80 (from
a header file). I have two functions so far, CPUReset(CPU z80) and CPUInfo(CPU a80). Those
to functions are the prototypes. CPUReset is used to set all the processor registers to 0x0000 or
0 and CPUInfo is used to print what's contained inside the processor's registers. Now, later
on in my main program, I'm calling the function CPUReset() like this:

CPUReset(Z80);

because I'm trying to clear all the registers out. Then, I'm calling the function CPUInfo just to
check and see if the registers have been cleared. I called it like this:

CPUInfo(Z80);

But the weird effect is that the registers will contain these bizzare numbers instead of all 0's like
I told it to in CPUReset(Z80). And yes, I did it in the order of

CPUReset(Z80);
CPUInfo(Z80);

Then, for debugging purposes, instead of declaring the Z80 cpu structure inside of main, I declared
if globally and the program worked. Why is this? I can still work with the Z80 being global but
I prefered that it had been inside the main function so it would be treated as local. How come
CPUInfo() will properly display the Z80 registers but CPUReset() won't reset all the registers
to 0? Why did it need to be global in order to reset the registers? I was passing Z80 along
inside the function parameters.

Please help,

Chris :o)
 
Chris
  • Guest
Reply with quote
Nevermind, problem solved
Post Posted: Thu Oct 28, 1999 7:19 am
Damn, I feel so dumb! But, I guess I should've paid more attention to the wording in those C books.
See, I declared a function like this:

void CPUReset(CPU a80);

The way that's declared, CPUReset dosen't return any values (void), but it passes the structured variable
a80 into the main function. So, if I declared a local variable in the main function called Z80, I
could pass it's variables to the function, but any changes made inside of the CPUReset() would
be forgotten once the function was complete; simply because I wasn't returning any values. I
thought that if you pass a variable via parameter inside a function that everything would automatically
come into place but I was wrong. When you create a function like the one stated above, before
the variable is passed into the function, it is pushed to the stack. No matter what changes you do
to the variable inside of the function, when it terminates, the original value is then popped or
returned to the passed variable. So if I did this:

void SetValue(int i);
SetValue()
{
i=10;
}

void main()
{
int a;
a = 20;
SetValue(a);
}

When you execute those instructions above, even though you're passing a to SetValue(), and you're
telling a to equal 10, the value of a will be erased back to it's original value before; which was 20.
That's the way function prototyping was designed. To be passed but not overwritten.

After a couple hours of heavy thought, and reading about the stack, it hit all hit me like common
sense. In order to change the value of a variable declared from another function inside another
function, you must do it 2 ways:

*The variable must be declared global or
*The value must not be passed but returned directly to itself from within another function.

So, I re-wrote the function from:

void CPUReset(CPU a80);
[to]
CPU CPUReset(void);

So, instead of merly passing values, CPUReset can now return values, directly or indirecly. I chose
to use the direct method by doing this:

Z80 = CPUReset();

And inside of the CPUReset() function I changed it to:

CPU CPUReset()
{
CPU a80; //Dummy variable used to return values.
a80.AF = 0;
a80.BC = 0;
[and so on...]

return(a80);
}

So now, Z80 will equal what a80 was equal to and a80 will be erased since the function has been
terminated. That's the direct method. There's probably an indirect way to do it but I don't think
you can pass structures to other structures; not unless you break it down and pass variable to
variable. It all makes sense.

Chris :o)
 
Limbs a Flyin'
  • Guest
Reply with quote
Re: Nevermind, problem solved
Post Posted: Thu Oct 28, 1999 1:08 pm
Quote
> So if I did this:

> void SetValue(int i);
> SetValue()
> {
> i=10;
> }

(been a while since i wrote anything, so forgive me if this is wrong - but it should convey the concept even if i typed it wrong)

void SetValue(int *i);
SetValue()
{
i=10;
}


Quote
> void main()
> {
> int a;
> a = 20;
> SetValue(a);
> }


void main()
{
int a;
a = 20;
SetValue(&a);
}

this way the setvalue function works directly on your variable without creating a temporary one. i hope i handled the pointers correctly


Quote
> *The variable must be declared global or
> *The value must not be passed but returned directly to itself from within another function.

*use a pointer to the address of the variable so other functions can work on it directly (due to them knowing where in ram the variable is)

using a function that creates a new variable or copy of a variable and work on it then returns it to the previous function to be copied onto the existing variable is not the ideal way. sounds complicated, and it requires extra overhead.
eg;
1) a new variable of the same type gets created - may or may not get its contents filled with an existings variables data (eg was it passed an argument etc) - some ram needs to be aloccated

2) work gets done on the new vairable

3) new variables data gets copied into the existing variable

4) new variable is destroyed


passing the address of the existing variable means that only the 2nd step needs to occur. for what you are doing its not a big deal. but it would be if you were doing it often on large datatypes (requires extra cpu time, ram, can cause memory fragmentation)

of course i could be wrong about the whole thing ;)
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Suggestion
Post Posted: Thu Oct 28, 1999 2:37 pm
Get your C book and re-read the chapter talking about pointer. They are useful for millions of things including that one.
Basically when you pass a variable the variable is pushed into the stack and popped inside of the functions, so it is a COPY of the variable and if you modify it, it won't be changed when quitting the function. So you can pass the address of the variable (&blabla) and then modify stuff directory at that address (*blabla or blabla->inside).
  View user's profile Send private message Visit poster's website
Eric
  • Guest
Reply with quote
Re: Nevermind, problem solved
Post Posted: Thu Oct 28, 1999 4:24 pm
Zoop and Limbs a Flyin' are correct. The method you've chosen, while sound, is rather slow. Given the nature of the procedures (Reset() being relatively rare, and Info() being used for, presumably debugging purposes, and so not affecting the main emulation loop) speed is not a primary concern. However, I'm sure there will be instances where you want to attempt the same kind of parameter passing in an area where execution speed is critical. A technique to improve the performance of your code is to use pointers when passing large data structures as parameters.

Because using pointers are tricky, I've outlined the approach below. I've used specific examples of CPUReset and CPUInfo, but the technique can be used anywhere.

Declare CPUReset to accept the address (pointer) of a Z80 structure:

void CPUReset(*Z80); /* The * in front of Z80 denotes a pointer to a Z80 structure.*/


Also, declare CPUInfo to accept the address (pointer) of a Z80 structure:

void CPUInfo(*Z80); /* The * in front fo Z80 denotes a pointer to a Z80 structure.*/



Now, you would define your CPUReset and CPUInfo function as follows:


void CPUReset(*Z80 theZ80)
{
*theZ80.AF = 0; /* The * dereferences the pointer. This simply means accessing the memory pointed to by 'theZ80'.*/
.
.
*theZ80.PC = 0;
};


Similarly, your CPUInfo function might look something like this:


void CPUInfo(*Z80 theZ80)
{
printf("AF Reg: %04X", *theZ80.AF;
.
.
printf("PC Reg: %04X", *theZ80.PC;
};


Basically, the functions now pass a single variable onto the stack, rather than pushing a whole new Z80 structure onto the stack. This can be a serious performance boost.

A final note, I'm not terribly familiar with C, but I do believe the '->' operator is available. It is used explicity when dereferencing a pointer to a structure. For example instead of typing *theZ80.AF the arrow operation allows you to type theZ80->AF. You may want try this to see if you compiler (or C) supports this operator.

Good luck.


Eric Quinn
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
A little correction
Post Posted: Fri Oct 29, 1999 11:58 am
Quote
> (been a while since i wrote anything, so forgive me if this is wrong - but it should convey the concept even if i typed it wrong)
> void SetValue(int *i);
> SetValue()
> {
> i=10;
> }

The i=10 line should be *i=10
i is the pointer itself.
*i is the data of type "int" (as there is no cast here) stored at sddress i
(and &i is the address of the pointer)
  View user's profile Send private message Visit poster's website
Chris
  • Guest
Reply with quote
I understand
Post Posted: Sat Oct 30, 1999 11:48 pm
I figured you needed to use a pointer if you're passing a pointer. I used it and it works. But, I always
feel so unceratain with pointers. Their so hard to imagine. Ahh well, it works.

Thanks,

Chris
 
Reply to topic



Back to the top of this page

Back to SMS Power!