โชคไม่ดีที่ใน cross platform, cross compiler environment ไม่มีวิธีการที่เชื่อถือได้เพียงวิธีเดียวในการรวบรวมเวลา
- ทั้ง _WIN32 และ _WIN64 สามารถบางครั้งทั้งสองไม่ได้กำหนดถ้าการตั้งค่าโครงการมีข้อบกพร่องหรือเสียหาย (โดยเฉพาะอย่างยิ่งใน Visual Studio 2008 SP1)
- โครงการที่ชื่อว่า "Win32" สามารถตั้งค่าเป็น 64- บิตได้เนื่องจากข้อผิดพลาดของการกำหนดค่าโครงการ
- ใน Visual Studio 2008 SP1 บางครั้ง Intellisense จะไม่ทำให้ส่วนที่ถูกต้องของรหัสเป็นไปตาม #define ปัจจุบัน สิ่งนี้ทำให้เป็นการยากที่จะดูว่า #define ใดถูกใช้ในเวลารวบรวม
ดังนั้นวิธีการที่เชื่อถือได้เพียงวิธีเดียวคือการรวมการตรวจสอบง่าย ๆ 3 รายการ :
- 1) การตั้งค่าเวลารวบรวมและ;
- 2) การตรวจสอบรันไทม์และ;
- 3) การตรวจสอบรวบรวมเวลาที่แข็งแกร่ง
ตรวจสอบง่าย 1/3: การตั้งค่าเวลาคอมไพล์
เลือกวิธีการใด ๆ เพื่อตั้งค่าตัวแปร #define ที่ต้องการ ฉันแนะนำวิธีการจาก @JaredPar:
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
ตรวจสอบง่าย 2/3: การตรวจสอบรันไทม์
ใน main () ให้ตรวจสอบอีกครั้งเพื่อดูว่า sizeof () สมเหตุสมผลหรือไม่:
#if defined(ENV64BIT)
if (sizeof(void*) != 8)
{
wprintf(L"ENV64BIT: Error: pointer should be 8 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 64-bit mode.\n");
#elif defined (ENV32BIT)
if (sizeof(void*) != 4)
{
wprintf(L"ENV32BIT: Error: pointer should be 4 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 32-bit mode.\n");
#else
#error "Must define either ENV32BIT or ENV64BIT".
#endif
การตรวจสอบง่าย 3/3: การตรวจสอบเวลารวบรวมอย่างมีประสิทธิภาพ
กฎทั่วไปคือ "ทุก #define ต้องลงท้ายด้วย #else ซึ่งสร้างข้อผิดพลาด"
#if defined(ENV64BIT)
// 64-bit code here.
#elif defined (ENV32BIT)
// 32-bit code here.
#else
// INCREASE ROBUSTNESS. ALWAYS THROW AN ERROR ON THE ELSE.
// - What if I made a typo and checked for ENV6BIT instead of ENV64BIT?
// - What if both ENV64BIT and ENV32BIT are not defined?
// - What if project is corrupted, and _WIN64 and _WIN32 are not defined?
// - What if I didn't include the required header file?
// - What if I checked for _WIN32 first instead of second?
// (in Windows, both are defined in 64-bit, so this will break codebase)
// - What if the code has just been ported to a different OS?
// - What if there is an unknown unknown, not mentioned in this list so far?
// I'm only human, and the mistakes above would break the *entire* codebase.
#error "Must define either ENV32BIT or ENV64BIT"
#endif
อัปเดต 2017-01-17
ความคิดเห็นจาก@AI.G
:
4 ปีต่อมา (ไม่ทราบว่าเป็นไปได้มาก่อนหรือไม่) คุณสามารถแปลงการตรวจสอบเวลาทำงานเป็นการรวบรวมเวลาโดยใช้การยืนยันแบบคงที่: static_assert (sizeof (void *) == 4); ตอนนี้มันก็ทำตอนรวบรวม :)
ภาคผนวกก
อนึ่งกฎดังกล่าวสามารถปรับให้ฐานข้อมูลทั้งหมดของคุณเชื่อถือได้มากขึ้น:
- คำสั่ง if () ทุกคำลงท้ายด้วย "else" ซึ่งสร้างคำเตือนหรือข้อผิดพลาด
- คำสั่ง switch () ทุกคำลงท้ายด้วย "default:" ซึ่งสร้างคำเตือนหรือข้อผิดพลาด
เหตุผลที่ทำให้การทำงานดีคือมันบังคับให้คุณคิดทุกกรณีล่วงหน้าและไม่พึ่งพาตรรกะ (บางครั้งมีข้อบกพร่อง) ในส่วน "อื่น" เพื่อรันโค้ดที่ถูกต้อง
ฉันใช้เทคนิคนี้ (ท่ามกลางคนอื่น ๆ ) เพื่อเขียนโครงการ 30,000 เส้นที่ทำงานได้อย่างไร้ที่ตินับตั้งแต่วันที่มันถูกนำไปใช้ในการผลิตครั้งแรก (นั่นคือ 12 เดือนที่แล้ว)