การหา 32 vs 64 บิตใน C ++


136

ฉันกำลังมองหาวิธีที่เชื่อถือได้ตรวจสอบว่ารหัส C ++ จะถูกรวบรวมใน 32 vs 64 บิต เราเกิดขึ้นกับสิ่งที่เราคิดว่าเป็นวิธีแก้ปัญหาที่สมเหตุสมผลโดยใช้มาโคร แต่ก็อยากรู้ว่าคนอื่นจะนึกถึงกรณีที่อาจล้มเหลวหรือมีวิธีที่ดีกว่าในการทำเช่นนี้ โปรดทราบว่าเรากำลังพยายามทำสิ่งนี้ในสภาพแวดล้อมคอมไพเลอร์แบบหลายแพลตฟอร์ม

#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif

#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif

ขอบคุณ


8
หากคุณใส่ใจสิ่งที่ขนาดของสถาปัตยกรรมของคุณจริงๆแล้วอย่ามองข้ามความเป็นไปได้ที่ไม่ใช่ 32 หรือ 64 บิต คุณรู้หรือไม่ว่ามีสถาปัตยกรรมแบบ 16 และ 128 บิต
alex tingle

ความแตกต่างระหว่างการทำงานแบบ 64 บิตและแบบ 32 บิตคืออะไร
peterchen

2
คุณไม่ควรปรับเงื่อนไขนี้ในความกว้างของคำของแพลตฟอร์มเป้าหมาย ให้ใช้ขนาดของประเภทข้อมูลที่เกี่ยวข้องโดยตรงเพื่อกำหนดว่าต้องทำอย่างไร stdint.hอาจเป็นเพื่อนของคุณหรือคุณอาจจำเป็นต้องพัฒนาแนวความคิดที่เหมาะสมของคุณเอง
Phil Miller

การทดสอบนี้ดูเหมือนจะไม่ทำงานบน Visual Studio 2008 SP1 มันติดอยู่ที่ "IS64BIT" สำหรับทั้ง 32- บิตและ 64- บิต
Contango

คำตอบ:


99

น่าเสียดายที่ไม่มีมาโครข้ามแพลตฟอร์มซึ่งกำหนด 32/64 บิตในคอมไพเลอร์หลัก ฉันพบวิธีที่มีประสิทธิภาพที่สุดในการทำสิ่งต่อไปนี้

ก่อนอื่นฉันเลือกตัวแทนของตัวเอง ฉันชอบ ENVIRONMENT64 / ENVIRONMENT32 จากนั้นฉันก็พบว่าคอมไพเลอร์หลักทั้งหมดใช้ในการพิจารณาว่ามันเป็นสภาพแวดล้อม 64 บิตหรือไม่และใช้เพื่อตั้งค่าตัวแปรของฉัน

// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif

// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif

อีกเส้นทางที่ง่ายขึ้นคือการตั้งค่าตัวแปรเหล่านี้จากบรรทัดคำสั่งคอมไพเลอร์


3
มีคอมไพเลอร์อื่น ๆ นอกเหนือจาก GCC และ VS ตัวอย่างเช่น QNX และ GHS มาถึงใจ (แม้ว่าฉันสงสัยว่า QNX มีการกำหนดเวลาแบบเดียวกันกับ GCC) นอกจากนี้คุณยังลืมสถาปัตยกรรม MIPS64 และ IA64 ในการตรวจสอบ GCC ของคุณ
รอม

14
@Rom มากกว่า 2 คอมไพเลอร์และสถาปัตยกรรม นี่เป็นเพียงตัวอย่างของวิธีการแก้ไขปัญหาไม่ใช่วิธีการแก้ปัญหาที่สมบูรณ์
JaredPar

2
ฉันพูดว่า "มักจะ" "อุดมคติ" น่าจะสมจริงยิ่งกว่า
Steve Jessop

7
ฉันคิดว่าคุณควรใช้ "#if ที่กำหนดไว้ ( win32 ) || define (_WIN64)" ฯลฯ
KindDragon

3
#if _WIN32 || _WIN64... #elif __GNUC__... #else # error "Missing feature-test macro for 32/64-bit on this compiler."?
Davislor

100
template<int> void DoMyOperationHelper();

template<> void DoMyOperationHelper<4>() 
{
  // do 32-bits operations
}

template<> void DoMyOperationHelper<8>() 
{
  // do 64-bits operations
}

// helper function just to hide clumsy syntax
inline void DoMyOperation() { DoMyOperationHelper<sizeof(size_t)>(); }

int main()
{
  // appropriate function will be selected at compile time 
  DoMyOperation(); 

  return 0;
}

2
จะเกิดอะไรขึ้นถ้า size_t ไม่ใช่ 4 หรือ 8
Jesper

16
@Jesper จากนั้นคุณจะได้รับข้อผิดพลาดลิงก์ในตัวอย่างด้านบน หรือคุณสามารถใช้ DoMyOperation สำหรับกรณีนี้ได้
Kirill V. Lyadvinsky

1
ใช้แม่แบบเนียนและรุ่งโรจน์สำหรับการทดสอบสิ่งที่สำคัญ (ขนาดของบางประเภท) มากกว่าความสัมพันธ์
Phil Miller

2
ระวังการใช้ size_t สำหรับสิ่งนี้ คุณสามารถมีปัญหาที่ไม่ตรงกับขนาดตัวชี้ (เช่นบนแพลตฟอร์มที่มีขนาดตัวชี้มากกว่าหนึ่ง)
Logan Capaldo

8
มาตรฐานบอกว่าขนาดของsize_tมีขนาดใหญ่พอที่จะเก็บขนาดของวัตถุที่จัดสรรในระบบ โดยปกติจะเป็นสิ่งที่คุณต้องการรู้ในขณะที่รวบรวมเงื่อนไข ถ้ามันไม่ได้เป็นสิ่งที่คุณต้องการคุณสามารถใช้ข้อมูลโค้ดนี้กับบางประเภทอื่น ๆ size_tแทน void*ยกตัวอย่างเช่นมันอาจจะเป็น
Kirill V. Lyadvinsky

44

โชคไม่ดีที่ใน 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 เดือนที่แล้ว)


sizeof(void*)มันได้รับการแก้ไขในเวลารวบรวมหรือรันไทม์? if(8!=8){...}ถ้ามันเป็นที่รวบรวมเวลาแล้วที่เวลาทำงานตรวจสอบจะเป็น
Ameen

@ameen มันได้รับการแก้ไขในเวลาทำงาน จุดประสงค์ของการตรวจสอบนี้คือเพื่อให้แน่ใจว่าโปรแกรมออกจากด้วยข้อผิดพลาดที่เหมาะสมหากพยานไม่ได้เป็นสิ่งที่คาดหวัง ซึ่งหมายความว่าผู้พัฒนาสามารถแก้ไขข้อผิดพลาดนี้ได้ทันทีแทนที่จะพยายามวิเคราะห์ข้อบกพร่องที่ละเอียดอ่อนที่ปรากฏขึ้นในภายหลัง
Contango

3
4 ปีต่อมา (ไม่ทราบว่ามันเป็นไปได้ก่อนหน้านี้) static_assert(sizeof(void*) == 4);คุณสามารถแปลงตรวจสอบระยะเวลาในการรวบรวมครั้งเดียวใช้ยืนยันแบบคงที่: ตอนนี้มันทำในเวลารวบรวม :)
อัลจี

1
static_assert(sizeof(void*) * CHAR_BIT == 32)แสดงออกและถูกต้องทางเทคนิคมากขึ้น (แม้ว่าฉันจะไม่ทราบสถาปัตยกรรมใด ๆ ที่ไบต์มีจำนวนบิตที่แตกต่างกันกว่า 8)
Xeverous

1
ดูคำตอบของฉันด้านล่างซึ่งรวมคำตอบที่ยอดเยี่ยมนี้กับ " Better Macros, Better Flags " จาก Fluent C ++
โลหะ

30

stdint.hคุณควรจะสามารถที่จะใช้แมโครที่กำหนดไว้ใน โดยเฉพาะอย่างยิ่งINTPTR_MAXเป็นค่าที่คุณต้องการ

#include <cstdint>
#if INTPTR_MAX == INT32_MAX
    #define THIS_IS_32_BIT_ENVIRONMENT
#elif INTPTR_MAX == INT64_MAX
    #define THIS_IS_64_BIT_ENVIRONMENT
#else
    #error "Environment not 32 or 64-bit."
#endif

บางคน (ทั้งหมด?) stdint.hรุ่นของคอมไพเลอร์ไมโครซอฟท์ไม่ได้มาด้วย ไม่แน่ใจว่าทำไมเพราะมันเป็นไฟล์มาตรฐาน นี่คือรุ่นที่คุณสามารถใช้ได้:http://msinttypes.googlecode.com/svn/trunk/stdint.h


4
ทำไมถึงไม่มี stdint.h สำหรับ Microsoft เพราะมันถูกนำมาใช้กับมาตรฐาน C99 และ Microsoft ดูเหมือนว่าจะมีความเกลียดชังการใช้งานแม้กระทั่งสิ่งที่ง่ายที่สุดจาก C99 แม้แต่สิ่งที่ง่ายของไลบรารีที่ไม่ต้องการเปลี่ยนแปลงคอมไพเลอร์ แม้แต่สิ่งที่ทำไปแล้วเมื่อรวบรวมสำหรับ C ++ (เช่นการประกาศหลังข้อความสั่ง) ฉันรู้ว่ามันต้องมีการทดสอบ ฯลฯ แต่ฉันก็รู้ด้วยเช่นกันว่า MS ได้รับ (หรือเคยได้รับ) ห้องสมุดที่เป็นธรรมจาก Dinkumware / Plauger และ Dinkumware มีห้องสมุด C99 หลายปี
ไมเคิลเสี้ยน

2
VC ++ 2010 (เบต้า 1 อยู่แล้ว) มีและ<stdint.h> <cstdint>สำหรับสถานะปัจจุบันของกิจการ - VC ++ อินเตอร์เน็ตห้องสมุดจาก Dinkumware (ยังคงไม่ - TR1 ถูกนำมาจากที่นั่นเช่นกัน) แต่จากสิ่งที่ผมจำได้อ่านบน VCBlog มันผ่าน refactoring อย่างมีนัยสำคัญอย่างเป็นธรรมในการรวบรวมหมดจดด้วย/clrการทำงานกับทุก MSVC ประเภทที่ไม่ได้มาตรฐานเช่น__int64และอื่น ๆ - ซึ่งเป็นเหตุผลว่าทำไมมันไม่ง่ายเหมือนการเอามันมาใส่ในคอมไพเลอร์เวอร์ชั่นถัดไป
Pavel Minaev

2
นี่ทำให้ฉันได้คำตอบที่ถูกต้อง แต่ฉันคิดว่าคุณควรเปรียบเทียบกับ UINT64_MAX ไม่ใช่ INT64_MAX ฉันใช้ SIZE_MAX == UINT64_MAX - ปัญหาเดียวกัน
Arno Duvenhage

15

สิ่งนี้จะไม่ทำงานบน Windows สำหรับการเริ่มต้น longs และ ints มีทั้ง 32 บิตไม่ว่าคุณจะคอมไพล์สำหรับ windows 32 บิตหรือ 64 บิต ฉันคิดว่าการตรวจสอบว่าขนาดของตัวชี้เป็น 8 ไบต์น่าจะเป็นเส้นทางที่เชื่อถือได้มากกว่าหรือไม่


2
แต่น่าเสียดายที่ sizeof เป็นสิ่งต้องห้ามใน #if สั่ง (ถ้าคุณคิดเกี่ยวกับมัน preprocessor มีวิธีที่จะบอกไม่ได้)
เฟรม

อ้างว่าเป็นเหตุผลที่ผมทิ้งมันไว้ที่แนะนำการตรวจสอบขนาดของตัวชี้มากกว่าใช้ sizeof - ฉันไม่สามารถคิดวิธีแบบพกพาที่จะทำมันปิดด้านบนของหัวของฉัน ...
mattnewport

3
คำถามไม่ได้ (ยัง) บอกว่ามันมีที่จะทำในช่วงเวลาก่อนการประมวลผล คอมไพเลอร์ส่วนใหญ่ที่มีการปรับให้เหมาะสมจะทำหน้าที่ได้ดีในการกำจัดรหัสที่ตายแล้วแม้ว่าคุณจะ "ปล่อยไว้จนกว่าจะถึงเวลาใช้งาน" ด้วยการทดสอบเช่นsizeof(void*) == 8 ? Do64Bit() : Do32Bit();นี้ ที่ยังคงสามารถใช้ฟังก์ชันที่ไม่ได้ใช้ในไบนารีได้ แต่นิพจน์นั้นอาจถูกรวบรวมเพื่อเรียกไปยังฟังก์ชัน "right"
Steve Jessop

1
@onebyone ที่แก้ปัญหาการเรียกใช้ฟังก์ชันได้ แต่ถ้าฉันต้องการประกาศตัวแปรชนิดอื่นตามแพลตฟอร์มที่จะต้องทำที่ preprocessor เว้นแต่คุณต้องการประกาศหลายตัวแปรและใช้ตัวแปร if ( ซึ่งก็จะได้รับการปรับออกหากพวกเขาไม่ได้ใช้ แต่จะไม่เป็นที่น่าพอใจมากในรหัส)
Falaina

1
ถ้าอย่างนั้นคุณพูดถูกการแสดงออกอย่างคงที่ในเงื่อนไขนั้นไม่ดี วิธีการของคิริลล์สามารถทำสิ่งที่คุณต้องการได้ แต่:template<int> struct Thing; template<> struct Thing<4> { typedef uint32_t type; }; template<> struct Thing<8> { typedef uint64_t type; }; typedef Thing<sizeof(void*)>::type thingtype;
Steve Jessop

9

คุณสามารถทำได้:

#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif

1
ในสภาพแวดล้อมการเขียนโปรแกรมจำนวนมากสำหรับภาษา C และ C ที่ได้มาบนเครื่อง 64 บิตตัวแปร "int" ยังคงมีความกว้าง 32 บิต แต่จำนวนเต็มและตัวชี้แบบยาวนั้นกว้าง 64 บิต สิ่งเหล่านี้อธิบายว่ามีตัวแบบข้อมูล LP64 unix.org/version2/whatsnew/lp64_wp.html
Hermes

6
Try this:
#ifdef _WIN64
// 64 bit code
#elif _WIN32
// 32 bit code
#else
   if(sizeof(void*)==4)

       // 32 bit code
   else 

       // 64 bit code   
#endif

7
รหัสนี้ไม่ถูกต้อง บน 64- บิตทั้ง _WIN32 และ _WIN64 ถูกกำหนด หากคุณหันไปรอบ ๆ (ตรวจสอบครั้งแรกสำหรับ _WIN64) มันใช้งานได้แน่นอน
BertR

4

"คอมไพล์ใน 64 บิต" ไม่ได้ถูกนิยามไว้อย่างดีใน C ++

c ++ ชุดเฉพาะข้อ จำกัด ที่ต่ำกว่าสำหรับขนาดเช่น int void *และยาว ไม่มีการรับประกันว่า int เป็น 64 บิตแม้เมื่อรวบรวมสำหรับแพลตฟอร์ม 64 บิต รูปแบบที่ช่วยให้เช่น 23 บิตintและsizeof(int *) != sizeof(char *)

มีรูปแบบการเขียนโปรแกรมที่แตกต่างกันสำหรับแพลตฟอร์ม 64 บิต

ทางออกที่ดีที่สุดของคุณคือการทดสอบเฉพาะแพลตฟอร์ม การตัดสินใจแบบพกพาที่ดีที่สุดอันดับสองของคุณจะต้องเจาะจงมากขึ้นในสิ่งที่ 64 บิต


3

วิธีการของคุณไม่ได้ไกลเกินไป แต่คุณเป็นเพียงการตรวจสอบว่าlongและintมีขนาดเดียวกัน ในทางทฤษฎีทั้งคู่อาจเป็น 64 บิตซึ่งในกรณีนี้เช็คของคุณจะล้มเหลวโดยสมมติว่าทั้งสองเป็น 32 บิต นี่คือการตรวจสอบที่ตรวจสอบขนาดจริง ๆ ของตัวเองไม่ใช่ขนาดที่เกี่ยวข้อง:

#if ((UINT_MAX) == 0xffffffffu)
    #define INT_IS32BIT
#else
    #define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
    #define LONG_IS32BIT
#else
    #define LONG_IS64BIT
#endif

โดยหลักการคุณสามารถทำสิ่งนี้ได้ทุกประเภทที่คุณมีมาโครที่ระบบกำหนดด้วยค่าสูงสุด

โปรดทราบว่ามาตรฐานนั้นต้องlong longมีอย่างน้อย 64 บิตแม้ในระบบ 32 บิต


สิ่งหนึ่งที่ควรสังเกตสำหรับการกำหนด UINT_MAX และ ULONG_MAX คุณอาจต้องการมี#include <limits.h>ที่ไหนสักแห่งก่อน#ifการทดสอบ
Alexis Wilke

3

ผู้คนได้แนะนำวิธีการต่าง ๆ ที่จะพยายามตรวจสอบว่ามีการรวบรวมโปรแกรม32-bitหรือ64-bitไม่

และฉันต้องการเพิ่มว่าคุณสามารถใช้คุณสมบัติ c ++ 11 static_assertเพื่อให้แน่ใจว่าสถาปัตยกรรมเป็นสิ่งที่คุณคิดว่าเป็น ("เพื่อผ่อนคลาย")

ดังนั้นในสถานที่ที่คุณกำหนดมาโคร:

#if ...
# define IS32BIT
  static_assert(sizeof(void *) == 4, "Error: The Arch is not what I think it is")
#elif ...
# define IS64BIT
  static_assert(sizeof(void *) == 8, "Error: The Arch is not what I think it is")
#else
# error "Cannot determine the Arch"
#endif

static_assert(sizeof(void*) * CHAR_BIT == 32)มีความหมายมากขึ้นและถูกต้องทางเทคนิค (แม้ว่าฉันจะไม่ทราบว่าสถาปัตยกรรมใดที่ไบต์มีจำนวนบิตที่แตกต่างกันมากกว่า 8)
Xeverous

2

โค้ดด้านล่างทำงานได้ดีสำหรับสภาพแวดล้อมส่วนใหญ่ในปัจจุบัน:

  #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) &&     !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
    #define IS64BIT 1
 #else
    #define IS32BIT 1
#endif

3
โปรดทราบว่าคุณต้องได้รวมแล้ว_WIN64 <windows.h>ด้วย Visual C ++ มันจะดีกว่าที่จะใช้ในตัวกำหนดเรียบเรียง: _M_IX86, _M_X64, _M_ARM, _M_ARM64ฯลฯ
ชัค Walbourn

สำหรับ PowerPC ผมเชื่อว่าคุณต้องตรวจสอบ__ppc64__, และ__powerpc64__ _ARCH_PPC64ที่จับ AIX และแพลตฟอร์มอื่น ๆ เช่นกัน
jww

1

หากคุณสามารถใช้การกำหนดค่าโครงการในทุกสภาพแวดล้อมของคุณนั่นจะทำให้การกำหนดสัญลักษณ์ 64 และ 32 บิตเป็นเรื่องง่าย ดังนั้นคุณจะมีการกำหนดค่าโครงการเช่นนี้:

Debug
32- บิต Debug 32- บิต Debug 32-
บิต
64- บิต

แก้ไข: นี่คือการกำหนดค่าทั่วไปไม่ใช่การกำหนดค่าที่กำหนดเป้าหมาย เรียกพวกเขาทุกอย่างที่คุณต้องการ

ถ้าคุณทำอย่างนั้นไม่ได้ฉันชอบความคิดของเจเร็ด


หรือรวมทั้งสอง: ตรวจจับการกำหนดค่าอัตโนมัติบนคอมไพเลอร์ที่คุณรู้จัก แต่กลับไปดูที่ #define ที่ระบุในโครงการ / command-line / อะไรก็ตามที่คอมไพเลอร์ที่ไม่รู้จัก
Steve Jessop

4
โซลูชันเฉพาะ VisualStudio ของคุณจะช่วยด้วยคำถามข้ามแพลตฟอร์มของ OP ได้อย่างไร?
alex tingle

3
@ จอน: อืม พวกเขาไม่ได้รับการสนับสนุนในชนิดของสภาพแวดล้อมข้ามแพลตฟอร์มใด ๆตามคำนิยาม นอกจากจะเป็นคำจำกัดความของ MS ในการข้ามแพลตฟอร์ม - ทำงานบน Windows รุ่นใหม่
EFraim

1
@EFraim: ใช่คุณสามารถกำหนดเป้าหมาย 32- หรือ 64- บิตโดยใช้ VS แต่นั่นไม่ใช่สิ่งที่ฉันกำลังพูดถึง การกำหนดค่าโครงการทั่วไปและชื่อที่ฉันกำหนดให้ไม่มีอะไรเกี่ยวข้องกับแพลตฟอร์มเลย หากการกำหนดค่าโครงการเป็นแบบเฉพาะ VS นั่นเป็นความอัปยศเพราะมีประโยชน์มาก
Jon Seigel

1
ฉันคิดว่านี่เป็นคำตอบที่ถูก มีความน่าเชื่อถือมากกว่าการพยายามตรวจสอบอัตโนมัติ IDE ทั้งหมดที่ฉันเคยเห็นสนับสนุนฟีเจอร์นี้ในบางรูปแบบและฉันพนันว่าฉันไม่เคยเห็นมันรองรับด้วยเช่นกัน หากคุณใช้ make หรือ jam คุณสามารถตั้งค่าตัวแปรจากบรรทัดคำสั่งเมื่อเรียกใช้ตามปกติ

1

ฉันต้องการวางซอร์ส 32- บิตและ 64- บิตในไฟล์ต่าง ๆ จากนั้นเลือกไฟล์ต้นฉบับที่เหมาะสมโดยใช้ระบบบิลด์


2
-DBUILD_64BITนี้จะคล้ายกับมีการสร้างระบบให้คุณธงเช่น บ่อยครั้งสิ่งบางอย่างคล้ายกันมากกับทั้ง 32 และ 64 บิตดังนั้นการมีไว้ในไฟล์เดียวกันจึงสามารถใช้งานได้จริง
Alexis Wilke

การบำรุงรักษาไฟล์ต้นฉบับคู่นั้นมีข้อผิดพลาดเกิดขึ้นได้ง่าย IMO แม้แต่ #if 64 บิตขนาดใหญ่ .. รหัสทั้งหมดสำหรับ 64 บิต # อื่น .. รหัสทั้งหมดสำหรับ 32 บิต #endif นั้นดีกว่านั้น (# ถ้าบรรทัดโดยบรรทัดเหมาะในมุมมองของฉัน)
brewmanz

1

การยืมจากคำตอบที่ยอดเยี่ยมของContangoและรวมกับ " Better Macros, Better Flags " จาก Fluent C ++ คุณสามารถทำได้:

// Macro for checking bitness (safer macros borrowed from 
// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/)
#define MYPROJ_IS_BITNESS( X ) MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_##X()

// Bitness checks borrowed from https://stackoverflow.com/a/12338526/201787
#if _WIN64 || ( __GNUC__ && __x86_64__ )
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 1
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 0
#    define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x64)
    static_assert( sizeof( void* ) == 8, "Pointer size is unexpected for this bitness" );
#elif _WIN32 || __GNUC__
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 0
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 1
#    define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x86)
    static_assert( sizeof( void* ) == 4, "Pointer size is unexpected for this bitness" );
#else
#    error "Unknown bitness!"
#endif

จากนั้นคุณสามารถใช้มันเช่น:

#if MYPROJ_IS_BITNESS( 64 )
    DoMy64BitOperation()
#else
    DoMy32BitOperation()
#endif

หรือใช้มาโครพิเศษที่ฉันเพิ่ม:

MYPROJ_IF_64_BIT_ELSE( DoMy64BitOperation(), DoMy32BitOperation() );

0

ฉันกำลังเพิ่มคำตอบนี้เป็นกรณีการใช้งานและตัวอย่างที่สมบูรณ์สำหรับการตรวจสอบรันไทม์ที่อธิบายไว้ในคำตอบอื่นคำตอบอื่น

นี่เป็นวิธีที่ฉันใช้ในการสื่อความหมายถึงผู้ใช้ปลายทางไม่ว่าโปรแกรมจะถูกรวบรวมเป็น 64 บิตหรือ 32 บิต (หรืออื่น ๆ สำหรับเรื่องนั้น):

version.h

#ifndef MY_VERSION
#define MY_VERSION

#include <string>

const std::string version = "0.09";
const std::string arch = (std::to_string(sizeof(void*) * 8) + "-bit");

#endif

test.cc

#include <iostream>
#include "version.h"

int main()
{
    std::cerr << "My App v" << version << " [" << arch << "]" << std::endl;
}

รวบรวมและทดสอบ

g++ -g test.cc
./a.out
My App v0.09 [64-bit]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.