为了学习的目的,我最近查看了一个使用 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;
我不明白为什么,非常想知道为什么编译器会这样:
对于第二点, void* 没有大小信息,因此编译器不知道指针要增加多少。 它应该增加 sizeof(double) 吗? 只有通过类型信息,它才知道会发生什么。
编辑:实际上这也适用于你的第一点。编译器需要知道其递增的数据类型的大小。 Void* 没有大小信息,因此通过转换为 byte*,您可以让编译器知道它需要将指针增加 sizeof(byte) * wrtn。
Edit2:经过您的澄清,您似乎在问为什么 Reflector 将代码发出为 void* 而不是正确转换的类型(字节 *)。 这很可能是因为类型信息是从参数类型中提取的,并且在方法中有些天真地使用了。 这可能是 Reflector 的问题,而不是编译器的问题。
这个指针代码也有可能丢失它在 IL 中的类型信息,我还没有测试过它,但它可能不会将类型信息(除了数据大小之外)携带到 IL 中以便 Reflector 正确发出(正常“安全”IL 应始终具有此类型信息)。如果是这种情况,Reflector 可能默认为 void* 或最接近的推断类型。
为了学习的目的,我最近查看了一个现有的程序集(使用 Reflector)
这里唯一的问题是使用 Reflector - 显然,它不太擅长从 IL 推导原始 C# 代码。 IL 本身是正确的,并且没有强制转换(不需要强制转换 - 在 IL 中,您将指针和整数参数压入堆栈,然后执行加/减操作)。反光镜错误。