我在C#工作,通常为嵌入式项目编写支持程序。我从一个早已离开的人那里继承了一个项目,这是我的一个客户用来通过RS-232下载和上传Intel Hex文件到他们的一些主板的程序。这个程序很好地为他们工作了好几年,但是我正在研究的新板子没有,并且需要一些修改。
我打开了这个项目,发现了这个问题。新板在0x90000000-0x9007FFFF
范围内的地址处生成一些数据,C#代码使用int
类型作为地址数据;这是签名的,它错误地处理了0x80000000
上的地址。到现在为止还挺好。但后来我自大了。
我决定清理代码,用Int16 / UInt16 / Int32 / UInt32替换所有“int”,具体取决于用法。花了一段时间,但我认为它会使代码更清晰,更容易理解,并希望避免任何未来的错误。
代码停止工作。它花了我一天的大部分时间,它归结为这一行:
currseg = (HexSegment)hex_segments[HashEntry];
HexSegment类型是一个结构(是,结构,而不是类),
public struct HexSegment
{
UInt32 Address; // this is the fix I made, both were int
UInt32 Buf_idx;
}
hex_segments是一个HashTable。
最后,HashEntry是一个“int”,也被制成了UInt32
。
在调试器中我看到了这个:
如果你看不到图像,HashEntry的值是0x00000000
。如果我让调试器看到hex_segments[0]
,我会得到一个包含合法数据的MLV.HexSegment
。如果我让调试器看到hex_segments[HashEntry]
,我会得到null!
将HashEntry
改为Int32
解决了这个问题。
就像我说的,我是一名嵌入式程序员。对我来说,这是一个很大的谜。有没有人可以解释为什么会这样?
因为Hashtable是由对象索引而不是由int索引的。
public virtual object this[object key] { get; set; }
因此,如果使用键0作为Int32添加对象,则它将与添加0作为UInt32的对象不同。
看看这个:
UInt32 index = 0;
Int32 index2 = 0;
Hashtable t = new Hashtable();
t.Add(index, new { name = "matt" });
t.Add(index2, new { name = "Matt" });
var obj = t[index];
var obj2 = t[index2];
Console.WriteLine(obj);
Console.WriteLine(obj2);