۱۳۸۷/۱۱/۳۰

آيا برنامه نويس‌هاي دات نت بايد نگران دنياي 64 بيتي باشند؟


جواب ساده و كوتاه: خير!
كدمديريت شده‌ي شما در هر دو پلتفرم 32 بيتي - x86 و x64 بدون نياز به هيچگونه تغييري و بدون نگراني اجرا خواهد شد.
گزيده‌اي از MSDN :
اگر كد شما 100 درصد مديريت شده است (managed code ايي كه به صورت خالص از دات نت فريم ورك استفاده مي‌كند و هيچگونه وابستگي خارجي ديگري به كتابخانه‌هاي ديگر ندارد)، تنها با كپي شدن در يك محيط x64 داراي CLR ايي 64 بيتي (دات نت فريم ورك 64 بيتي)، بدون هيچگونه مشكلي اجرا خواهد شد.

سؤال: چرا و چگونه؟!
كامپايلرهاي دات نتي (تفاوتي نمي‌كند كه چه زباني مورد استفاده باشد)، كد شما را به IL‌ ترجمه مي‌كنند و IL اساسا دركي از پروسسور ندارد. JIT است كه در آخرين لحظه در اين مورد تصميم گيري مي‌كند.

اين نگراني از كجا حاصل شده است؟
نگارش R2 ويندوز 2008 سرور، فقط 64 بيتي خواهد بود و ويندوز سرور 2008 فعلي، آخرين سروري از مايكروسافت است كه هر دو نسخه‌ي 32 بيتي و 64 بيتي را دارد. بنابراين دير يا زود تمام برنامه نويس‌هاي ويندوزي "مجبور" خواهند شد دنياي 64 بيتي را تجربه كنند. (البته اگر تاكنون آن‌را تجربه نكرده‌اند)
و البته هنوز يك سري از محيط‌هاي توسعه، كامپايلر مخصوص 64 بيتي ندارند (مانند دلفي كه قرار است در طول سال جاري اولين تجربه‌ي 64 بيتي خود را ارائه دهد)

نكته:
در صفحه‌ي build ويژوال استوديو، شما مي‌توانيد نوع پلتفرم مورد نظر را نيز تعيين كنيد:



پيش فرض آن بر روي Any CPU‌ است و در اين حالت كد كامپايل شده‌ي شما بدون مشكل بر روي پلتفرم‌هايي كه مشاهده مي‌كنيد اجرا خواهد شد و تنها پيشنياز اجراي آن، نصب نسخه‌ي دات نت فريم ورك مخصوص آن پلتفرم است، بدون اينكه نياز باشد برنامه نويس نگران جزئيات خاصي در مورد خصوصيات ويژه‌ي آن پلتفرم‌ ويژه باشد.


سؤال: اگر كد ما خالص نبود چطور؟ (منظور اينكه 100 درصد دات نتي نبود)

حالت الف) اگر از كامپوننت‌هاي خارجي استفاده مي‌كنيد (حتي اگر 100 درصد دات نتي هم باشند) حتما اطمينان حاصل كنيد كه براي پلتفرم خاصي كامپايل نشده‌اند (همان Any CPU‌‌ مورد استفاده بوده)، زيرا كد شما كه براي تمام CPU ها كامپايل شده، در محيط 64 بيتي، تنها توانايي بارگذاري اسمبلي‌هاي 64 بيتي را خواهد داشت (64 بيتي رفتار مي‌كند) و با مواجه شدن با اسمبلي‌هايي كه براي يك پروسسور خاص ديگر كامپايل شده‌اند، با خطاي BadImageFormatException خاتمه مي‌يابد.

حالت ب) استفاده از API ويندوز يا DLL هاي غير دات نتي
بايد با هماهنگي با توليد كننده‌ي مربوطه حتما از نگارش 64 بيتي استفاده شود و همچنين برنامه‌ي شما بايد توانايي استفاده از اشاره‌گرهاي 64 بيتي را داشته باشد. اندازه‌ي نوع داده‌اي IntPtr در يك محيط 32 بيتي 4 است و در يك محيط 64 بيتي 8 خواهد بود (IntPtr.Size). اگر در حين اجراي ترجمه‌ي API يك كتابخانه به اشتباه بجاي استفاده از IntPtr از int‌ استفاده شده باشد، ممكن است كد شما در يك محيط 32 بيتي سال‌ها بدون مشكل اجرا شود، اما در اولين اجراي خود در يك محيط 64 بيتي، كرش خواهد كرد. (بدليل overflow حاصل)
IntPtr به اندازه‌ي كافي هوشمند است تا سايز خودش را مطابق پلتفرم تنظيم كند و مشكل ساز نشود.

مثال:

[DllImport("kernel32.dll")]
public static extern void GetSystemInfo([MarshalAs(UnmanagedType.Struct)] ref SYSTEM_INFO lpSystemInfo);

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO
{
internal _PROCESSOR_INFO_UNION uProcessorInfo;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public int lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort dwProcessorLevel;
public ushort dwProcessorRevision;
}

[StructLayout(LayoutKind.Explicit)]
public struct _PROCESSOR_INFO_UNION
{
[FieldOffset(0)]
internal uint dwOemId;
[FieldOffset(0)]
internal ushort wProcessorArchitecture;
[FieldOffset(2)]
internal ushort wReserved;
}

در اين مثال كه از API‌ ويندوز استفاده مي‌شود، به اشتباه نوع lpMaximumApplicationAddress‌ به صورت int تعريف شده است (بجاي IntPtr). اين كد بدون مشكل در يك برنامه‌ي 32 بيتي كار مي‌كند اما همين برنامه در يك محيط 64 بيتي يا كرش خواهد كرد يا مقدار lpMaximumApplicationAddress منفي گزارش مي‌شود.