如何维护 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 个字节才能开始接触其上的其他对象。当然,这些都是假设:您在这里处理未定义的行为。
因此,您实际上是在访问数组边界之外的内容,但由于它是不安全的代码,因此在执行此操作时您不会得到干净利落的异常,反而会产生奇怪的副作用。
但是无论如何,使用指针是一件很痛苦的事情,这就是一个例子。我建议您坚持使用托管内存。
我想不出更好的方式来表达这个问题的标题,所以如果有人推荐我可以更改它。
我正在编写一个 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 个字节才能开始接触其上的其他对象。当然,这些都是假设:您在这里处理未定义的行为。
因此,您实际上是在访问数组边界之外的内容,但由于它是不安全的代码,因此在执行此操作时您不会得到干净利落的异常,反而会产生奇怪的副作用。
但是无论如何,使用指针是一件很痛苦的事情,这就是一个例子。我建议您坚持使用托管内存。