为了学习目的,我最近查看了一个使用Win32 WriteFile的现有程序集(使用Reflector)。实施是:
Write(IntPtr handleFile, void* bufferData, uint length){
void* buffer = bufferData
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
// This does not compile, because of the cast but also simply because void* does not have += operators (it is unknown size).
buffer += (void*)wrtn;
len -= wrtn;
}
}
实际上最后两行是有问题的...例如,编译器抱怨你不能将uint转换为void *。另外,在void *上使用+ =或偶数+是不可能的,因为它不是已知的大小。
Write(IntPtr handleFile, void* bufferData, uint length){
byte* buffer = (byte*)bufferData
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
// This works! I can add to a byte*
buffer = buffer + wrtn; // I could also have used buffer += wrtn
len -= wrtn;
}
}
上面的代码确实有效,但最后几行仍然会编译为:
buffer += (byte*)wrtn;
我不明白为什么并且非常想知道编译器为什么会以这种方式运行:
答案 0 :(得分:1)
对于你的第二点,void *没有大小信息,所以编译器不知道增加指针的数量。它应该增加sizeof(double)吗?只有类型信息才知道会发生什么。
编辑:实际上这也适用于你的第一点。编译器需要知道其递增的数据类型的大小。 Void *没有大小信息,所以通过转换为字节*,让编译器知道它需要通过sizeof(byte)* wrtn递增指针。
Edit2:有了你的澄清,你似乎在问为什么Reflector将代码作为void *而不是正确的类型(byte *)发出。很可能这是由于从参数类型中提取的类型信息,并且在该方法中有点天真地使用。这可能是Reflector比编译器更多的问题。
这个指针代码也可能在IL中丢失了它的类型信息,我还没有测试过它,但是它可能不会将输入信息(除了数据的大小)带入IL,以便Reflector正确发出(正常'安全'IL应始终具有此类型信息)。如果是这种情况,Reflector可能默认为void *或最近的推断类型。
答案 1 :(得分:0)
为了学习目的,我最近查看了一个现有的程序集(使用Reflector)
这里唯一的问题是使用Reflector - 显然,从IL推断出原始的C#代码并不是那么好。 IL本身是正确的,并且没有强制转换(不需要强制转换 - 在IL中,您在堆栈上按下指针和整数参数,然后执行加/减)。反射器是错误的。