xan*_*tos 23
尝试:(
请注意,这是初始版本,请阅读下面的最终版本)
IntPtr xy = value;
int x = unchecked((short)xy);
int y = unchecked((short)((uint)xy >> 16));
Run Code Online (Sandbox Code Playgroud)
在unchecked通常是没有必要的(因为"默认" C#项目未选中)
请考虑以下是使用的宏的定义:
#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
Run Code Online (Sandbox Code Playgroud)
哪里WORD == ushort,DWORD == uint.我正在削减一些ushort->简短的转换.
附录:
一年半之后,经历了64位.NET的"变幻莫测",我同意Celess(但请注意,由于兼容性原因,99%的Windows消息仍然是32位,所以我不认为这个问题现在不是很大.未来更多,因为如果你想做某事,你应该正确地做.)
我唯一能做的就是:
IntPtr xy = value;
int x = unchecked((short)(long)xy);
int y = unchecked((short)((long)xy >> 16));
Run Code Online (Sandbox Code Playgroud)
而不是检查"是IntPtr4或8字节长",我采取最坏的情况(8字节长)并xy转换为long.随着一点点运气双投(至long再到short/对uint)将通过编译器优化(到底,在显式转换int的IntPtr是一个红色的鲱鱼......如果你使用它,你是把自己处于危险中您应该始终使用long转换,然后直接使用它/将其重新投射到您需要的位置,向未来的程序员展示您知道自己在做什么.
一个测试示例:http://ideone.com/a4oGW2(遗憾的是只有32位,但如果你有64位机器,你可以测试相同的代码)
Cel*_*ess 12
适用于32位和64位:
Point GetPoint(IntPtr _xy)
{
uint xy = unchecked(IntPtr.Size == 8 ? (uint)_xy.ToInt64() : (uint)_xy.ToInt32());
int x = unchecked((short)xy);
int y = unchecked((short)(xy >> 16));
return new Point(x, y);
}
Run Code Online (Sandbox Code Playgroud)
- 要么 -
int GetIntUnchecked(IntPtr value)
{
return IntPtr.Size == 8 ? unchecked((int)value.ToInt64()) : value.ToInt32();
}
int Low16(IntPtr value)
{
return unchecked((short)GetIntUnchecked(value));
}
int High16(IntPtr value)
{
return unchecked((short)(((uint)GetIntUnchecked(value)) >> 16));
}
Run Code Online (Sandbox Code Playgroud)
这些也有效:
int Low16(IntPtr value)
{
return unchecked((short)(uint)value); // classic unchecked cast to uint
}
int High16(IntPtr value)
{
return unchecked((short)((uint)value >> 16));
}
Run Code Online (Sandbox Code Playgroud)
- 要么 -
int Low16(IntPtr value)
{
return unchecked((short)(long)value); // presumption about internals
} // is what framework lib uses
int High16(IntPtr value)
{
return unchecked((short)((long)value >> 16));
}
Run Code Online (Sandbox Code Playgroud)
走另一条路
public static IntPtr GetLParam(Point point)
{
return (IntPtr)((point.Y << 16) | (point.X & 0xffff));
} // mask ~= unchecked((int)(short)x)
Run Code Online (Sandbox Code Playgroud)
- 要么 -
public static IntPtr MakeLParam(int low, int high)
{
return (IntPtr)((high << 16) | (low & 0xffff));
} // (IntPtr)x is same as 'new IntPtr(x)'
Run Code Online (Sandbox Code Playgroud)
接受的答案是C定义的良好翻译.如果直接处理原始'void*',那么大部分都可以.但是,当在.Net 64位执行环境中使用'IntPtr'时,'unchecked'不会阻止转换溢出异常从IntPtr内部抛出.未选中块并不会影响IntPtr的funcitons和运营商内部发生的转换.目前接受的答案表明使用'未经检查'并非必要.然而,使用'unchecked' 是绝对必要的,因为从较大类型转换为负值时总是如此.
在64位,从接受的答案:
var xy = new IntPtr(0x0FFFFFFFFFFFFFFF);
int x = unchecked((short)xy); // <-- throws
int y = unchecked((short)((uint)xy >> 16)); // gets lucky, 'uint' implicit 'long'
y = unchecked((short)((int)xy >> 16)); // <-- throws
xy = new IntPtr(0x00000000FFFF0000); // 0, -1
x = unchecked((short)xy); // <-- throws
y = unchecked((short)((uint)xy >> 16)); // still lucky
y = (short)((uint)xy >> 16); // <-- throws (short), no longer lucky
Run Code Online (Sandbox Code Playgroud)
在64位上,使用外推版本的DmitryG:
var ptr = new IntPtr(0x0FFFFFFFFFFFFFFF);
var xy = IntPtr.Size == 8 ? (int)ptr.ToInt64() : ptr.ToInt32(); // <-- throws (int)
int x = unchecked((short)xy); // fine, if gets this far
int y = unchecked((short)((uint)xy >> 16)); // fine, if gets this far
y = unchecked((short)(xy >> 16)); // also fine, if gets this far
ptr = new IntPtr(0x00000000FFFF0000); // 0, -1
xy = IntPtr.Size == 8 ? (int)ptr.ToInt64() : ptr.ToInt32(); // <-- throws (int)
Run Code Online (Sandbox Code Playgroud)
关于表现
return IntPtr.Size == 8 ? unchecked((int)value.ToInt64()) : value.ToInt32();
Run Code Online (Sandbox Code Playgroud)
IntPtr.Size属性返回一个常量作为编译时文字,如果跨程序集内联,则该常量是有效的.因此,JIT几乎可以将所有这些优化出来.也可以这样做:
return unchecked((int)value.ToInt64());
Run Code Online (Sandbox Code Playgroud)
- 要么 -
return unchecked((int)(long)value);
Run Code Online (Sandbox Code Playgroud)
- 要么 -
return unchecked((uint)value); // traditional
Run Code Online (Sandbox Code Playgroud)
并且所有这三个将始终调用IntPtr.ToInt64()的等效项.ToInt64()和'operator long'也可以内联,但不太可能.32位版本的代码比Size常量多得多.我认为顶部的解决方案可能在语义上更正确.同样重要的是要注意符号扩展工件,它会在像(long)int_val这样的东西上填充所有64位,尽管我已经在这里稍微掩饰了,但是可能另外影响32位的内联.
使用率
if (Low16(wParam) == NativeMethods.WM_CREATE)) { }
var x = Low16(lParam);
var point = GetPoint(lParam);
Run Code Online (Sandbox Code Playgroud)
下面显示的'安全'IntPtr模型用于未来的traverlers.
无需在32位上设置WIN32定义即可运行此操作,以获得64位IntPtr行为的可靠模拟.
public struct IntPtrMock
{
#if WIN32
int m_value;
#else
long m_value;
#endif
int IntPtr_ToInt32() {
#if WIN32
return (int)m_value;
#else
long l = m_value;
return checked((int)l);
#endif
}
public static explicit operator int(IntPtrMock value) { //(short) resolves here
#if WIN32
return (int)value.m_value;
#else
long l = value.m_value;
return checked((int)l); // throws here if any high 32 bits
#endif // check forces sign stay signed
}
public static explicit operator long(IntPtrMock value) { //(uint) resolves here
#if WIN32
return (long)(int)value.m_value;
#else
return (long)value.m_value;
#endif
}
public int ToInt32() {
#if WIN32
return (int)value.m_value;
#else
long l = m_value;
return checked((int)l); // throws here if any high 32 bits
#endif // check forces sign stay signed
}
public long ToInt64() {
#if WIN32
return (long)(int)m_value;
#else
return (long)m_value;
#endif
}
public IntPtrMock(long value) {
#if WIN32
m_value = checked((int)value);
#else
m_value = value;
#endif
}
}
public static IntPtr MAKELPARAM(int low, int high)
{
return (IntPtr)((high << 16) | (low & 0xffff));
}
public Main()
{
var xy = new IntPtrMock(0x0FFFFFFFFFFFFFFF); // simulate 64-bit, overflow smaller
int x = unchecked((short)xy); // <-- throws
int y = unchecked((short)((uint)xy >> 16)); // got lucky, 'uint' implicit 'long'
y = unchecked((short)((int)xy >> 16)); // <-- throws
int xy2 = IntPtr.Size == 8 ? (int)xy.ToInt64() : xy.ToInt32(); // <-- throws
int xy3 = unchecked(IntPtr.Size == 8 ? (int)xy.ToInt64() : xy.ToInt32()); //ok
// proper 32-bit lParam, overflow signed
var xy4 = new IntPtrMock(0x00000000FFFFFFFF); // x = -1, y = -1
int x2 = unchecked((short)xy4); // <-- throws
int xy5 = IntPtr.Size == 8 ? (int)xy4.ToInt64() : xy4.ToInt32(); // <-- throws
var xy6 = new IntPtrMock(0x00000000FFFF0000); // x = 0, y = -1
int x3 = unchecked((short)xy6); // <-- throws
int xy7 = IntPtr.Size == 8 ? (int)xy6.ToInt64() : xy6.ToInt32(); // <-- throws
var xy8 = MAKELPARAM(-1, -1); // WinForms macro
int x4 = unchecked((short)xy8); // <-- throws
int xy9 = IntPtr.Size == 8 ? (int)xy8.ToInt64() : xy8.ToInt32(); // <-- throws
}
Run Code Online (Sandbox Code Playgroud)