简体   繁体   中英

How do I maintain the value of members referred to by a pointer in C#?

I couldn't think of a better way to word the title of this question, so I can change that if recommended.

I'm writing a Space Invaders emulator as a learning project and I have encountered an issue when trying to test one of the op codes I implemented. Here is the test code:

public unsafe void InrBTest()
        {
            Processor8080 processor = new Processor8080();
            Processor8080* processorPtr = &processor;
            byte testMemory = 0x03;

            processorPtr->pc = 0x04;
            processorPtr->b = 0x38;
            //processorPtr->c = 0xFE;
            processorPtr->memory = &testMemory;
            processorPtr->memory[processorPtr->pc] = 0x04;
            emulator.Emulate8080OpCode(processorPtr);    
        }

As you can see, there is nothing crazy going on here. All I'm doing is setting up a Processor8080 object, getting a pointer to it, and then setting some values to test.

The problem is the second-to-last line: processorPtr->memory[processorPtr->pc] = 0x04; . After this line executes, all of the values that I had previously set get completely changed and I get crazy values for the fields in the Processor8080 object -- even values that hadn't previously been set.

Also, the memory field in the Processor8080 struct gets set to null. I have several other tests that are set up this exact way, but none of them encounter this issue; they all work fine. I'll put the code for the Processor8080 struct below for reference, but I don't think the issue is there.

I'm fairly new to this kind of programming, so it wouldn't surprise me if I've just missed something somewhere. The most confusing thing to me is that other tests I've written don't do this at all.

I'll post one of the others below to show you an example. Thanks for any help.

Processor8080 struct:

public struct ConditionCodes
    {
        [BitFieldLength(1)]
        public byte z;
        [BitFieldLength(1)]
        public byte p;
        [BitFieldLength(1)]
        public byte s;
        [BitFieldLength(1)]
        public byte cy;
        [BitFieldLength(1)]
        public byte ac;
        [BitFieldLength(3)]
        public byte pad;
    }
    public struct Processor8080
    {
        public byte a, b, c, d, e, h, l; //registers
        public ushort sp, pc; //stack pointer, program counter
        public unsafe byte* memory; //RAM
        public byte intEnable;
        public ConditionCodes cc;
    }

Example of a test that is working:

public void InxBTest()
        {
            //Tests the INX B (0x03) instruction
            unsafe
            {
                Processor8080 processor = new Processor8080();
                Processor8080* processorPtr = &processor;
                byte testMemory = 0x03;

                processorPtr->pc = 0x03;
                processorPtr->b = 0x38;
                processorPtr->c = 0xFE;
                processorPtr->memory = &testMemory;
                processorPtr->memory[processorPtr->pc] = 0x03;
                emulator.Emulate8080OpCode(processorPtr);

            }
        }

EDIT:

I have discovered that, as long as I don't set processorPtr->pc to a value greater that 0x03, there is no issue. I can't think of why that is, but if someone can shed some light, I'd greatly appreciate it.

It's a good old fashioned buffer overflow error.

You're assigning the address of a single byte to pc->memory :

processorPtr->memory = &testMemory;

Then, you're accessing that memory like an array:

processorPtr->memory[processorPtr->pc] = 0x03;

Problem is, here, processorPtr->pc is equal to 4, but the memory is only one byte long. Uh oh. Since it's memory on the stack, my guess is you're actually trampling over other values on the stack, and since your Processor8080 type is a struct, it lives on the stack, so you end up messing around with it.

If it appears to be working with values smaller than 4, it's probably because of padding or alignment. If your stack is 4 byte aligned, then you have to go at least 4 bytes to start touching other objects on it. Those are all suppositions, of course: you're dealing with undefined behavior here.

So, you're essentially accessing things outside the bounds of an array, but since it's unsafe code, you don't get a nice clean exception when doing it, instead you get weird side effects.

But anyway, working with pointers is a pain, and that's one example of it. I'd recommend you stick to managed memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM