如何维护 C# 中指针引用的成员的值?

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

我想不出更好的方式来表达这个问题的标题,所以如果有人推荐我可以更改它。

我正在编写一个 Space Invaders 模拟器作为一个学习项目,我在尝试测试我实现的其中一个操作代码时遇到了一个问题。这是测试代码:

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);    
        }

如您所见,这里没有发生任何疯狂的事情。我所做的只是设置一个 Processor8080 object,获取指向它的指针,然后设置一些值进行测试。

问题出在 second-to-last 行:processorPtr->memory[processorPtr->pc] = 0x04;。执行此行后,我之前设置的所有值都将完全更改,并且我得到了 Processor8080 object 中字段的疯狂值——甚至是之前未设置的值。

此外,Processor8080 结构中的 memory 字段被设置为空。我还有其他几个测试正是按照这种方式设置的,但是 none 其中遇到了这个问题;他们都工作正常。我将把 Processor8080 结构的代码放在下面以供参考,但我认为问题不在那里。

我对这种编程还很陌生,所以如果我只是错过了什么地方,我也不会感到惊讶。最让我困惑的是我写的其他测试根本不这样做。

我将 post 下面的其他人之一向您展示一个例子。感谢您的帮助。

Processor8080 结构:

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;
    }

有效的测试示例:

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);

            }
        }

编辑:

我发现,只要我不将 processorPtr->pc 设置为大于 0x03 的值,就没有问题。我想不出为什么会这样,但如果有人能提供一些启示,我将不胜感激。

这是一个很好的老式缓冲区溢出错误。

您正在将单个字节的地址分配给 pc->memory:

processorPtr->memory = &testMemory;

然后,您将像访问数组一样访问该内存:

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

问题是,在这里,processorPtr->pc等于4,但内存只有一个字节长。呃哦。因为它是堆栈上的内存,我猜你实际上是在践踏堆栈上的其他值,并且由于你的 Processor8080 类型是一个结构,它存在于堆栈上,所以你最终会弄乱它。

如果它似乎使用小于 4 的值,可能是因为填充或对齐。如果您的堆栈是 4 字节对齐的,那么您必须至少移动 4 个字节才能开始接触其上的其他对象。当然,这些都是假设:您在这里处理未定义的行为。

因此,您实际上是在访问数组边界之外的内容,但由于它是不安全的代码,因此在执行此操作时您不会得到干净利落的异常,反而会产生奇怪的副作用。

但是无论如何,使用指针是一件很痛苦的事情,这就是一个例子。我建议您坚持使用托管内存。