I am trying to learn some c++. To do this I have chosen to write an emulator. I had it up and running, but decided to try to make a better architecture. I have a strange problem that I don't understand. If I compile the following code (Visual C++ 2000 Express Edition) I get an error message: "Unhandled exception at 0x0041183f in test.exe: 0xC0000005: Access violation reading location 0x00000004."

If I cut the code from cpu.cpp and paste in main.cpp it is working. Can somebody try to explain to me what is the problem with my code/design?

main.h

typedef unsigned char u8;
typedef unsigned short u16;

// Forward declare the required classes
class Cpu;
class Memory;

class Gameboy
{
public:
	Cpu *cpu;
	Memory *memory;

	Gameboy();
	~Gameboy();
	void Start();
};

static Gameboy *gb;

class Memory
{
public:
	u8 read(u16 addr) const;
	void write(u16 addr, u8 value);
private:
	u8 _memory[0xffff];
};

class Cpu {
public:
	void Run();
};

main.cpp

#include <iostream>
#include "main.h"

int main(int argc, char *argv[])
{
    gb = new Gameboy();
	gb->Start();
	system("PAUSE");
	return 0;
}

u8 Memory::read(u16 addr) const { return _memory[addr];}
void Memory::write(u16 addr, u8 value) { _memory[addr] = value; }
Gameboy::Gameboy() { this->cpu = new Cpu(); this->memory = new Memory(); }
Gameboy::~Gameboy() { delete cpu; delete memory; }
void Gameboy::Start() {	cpu->Run(); }

cpu.cpp

#include <iostream>
#include "main.h"

void Cpu::Run() {
	gb->memory->write(0xff40, 0x10);
	printf("[Debug] 0xff40: %.2X\n", gb->memory->read(0xff40));
}

Recommended Answers

All 6 Replies

Where is my crystall ball? No codes in your snippet. You may present excellent function prototype but where is this function body?
It's interesting, can you help me right now: I have some troubles with my car (well, I haven't), help me, please! ;)

No need for crystal ball. All the code is there. I have pasted 3 files. The functions are small since I tried to only include what is nessessary to reproduce the problem.

main.h with all the class definitions and function prototypes. main.cpp contains all function, except for void Cpu::Run() which is in a separate file, cpu.cpp.

The reason for this is that if everything is in one file it is working, and the printf in void Cpu::Run() gives me the expected output. If I try to start separating the classes into individual files, I get the error message described. In this example I have only moved the void Cpu::Run() from main.cpp to cpu.cpp, and it is causing me problems.

Oh, I did not found these crumpled bodies, sorry.

It's so simple: you have declared static gb pointer in main.h (never, ever do it again). It's a module scope variable: gb from main.cpp is not the same as gb from cpu.cpp. That's all: you refer to nullptr initialized gb in cpu.cpp...

OK thanks for the reply. Seems like I misunderstood the 'static' a bit. How would I go ahead and declare this if I want it as a global variable? If I define it in a header file, the linker complains about it being declared several places.

What I want is a Gameboy class which contains memory, cpu etc classes. How can I then access functions in memory from e.g. cpu? Should I pass the *gb as part of the constructor or something.

Anyone have a prefered solution for that?

you never really want to define a global variable. if the variable is to travel around you can declare it in you main.cpp file in the int main() function as a pointer and then pass it around to your different functions and classes as a pointer.

void Cpu::Run(GameBoy * gb)

then you will have your gb object in main() and you can have it in Cpu::Run()

There are lots of possible solutions.
The worst: global variable.
main.h file:

extern Gameboy* gb; // global var declaration

main.cpp:

Gameboy* gb; // nullptr initial value (global var definition)

Another (more consistent) approach (variant):

class Debugger;
class Processor
{
    friend class Debugger; // future improvements...
public:
    Processor():busy(false) {}
    ...
    void Run();
    bool lock() { return busy?false:(busy=true); }
    vool locked() const { return busy; }
    void unlock() { busy = false; }
    ...
private:
    Cpu cpu;
    Memory memory;
    bool busy;
};
...
class Gameboy
{
public:
    Gameboy():proc(0) {}
    ...
    bool attach(Processor& p)
    {
        if (p.locked())
            return false;
        proc = &p;
        return p.lock();
    }
    Processor* detach()
    {
        Processor* p = proc;
        proc = 0;
        return p;
    }
    void Play();
    void Start() { Play(); } // (backward compatibility ;)
    ...
private:
    Processor* proc;
};

and so on...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.