ใน ISO C99 / C11 การกดพิมพ์แบบยูเนี่ยนเป็นสิ่งที่ถูกกฎหมายดังนั้นคุณสามารถใช้แทนการจัดทำดัชนีพอยน์เตอร์ไปยังอาร์เรย์ที่ไม่ใช่ (ดูคำตอบอื่น ๆ )
ISO C ++ ไม่อนุญาตให้ใช้การพิมพ์แบบยูเนียน  GNU C ++ เป็นส่วนขยายและฉันคิดว่าคอมไพเลอร์อื่น ๆ บางตัวที่ไม่รองรับส่วนขยาย GNU โดยทั่วไปรองรับการพิมพ์ยูเนี่ยน แต่นั่นไม่ได้ช่วยให้คุณเขียนโค้ดแบบพกพาได้อย่างเคร่งครัด
ด้วย gcc และ clang เวอร์ชันปัจจุบันการเขียนฟังก์ชันสมาชิก C ++ โดยใช้ a switch(idx)เพื่อเลือกสมาชิกจะเพิ่มประสิทธิภาพสำหรับดัชนีค่าคงที่เวลาคอมไพล์ แต่จะสร้าง asm ที่แตกแขนงแย่มากสำหรับดัชนีรันไทม์ ไม่มีอะไรผิดปกติswitch()สำหรับสิ่งนี้; นี่เป็นเพียงข้อผิดพลาดในการเพิ่มประสิทธิภาพที่ไม่ได้รับในคอมไพเลอร์ปัจจุบัน พวกเขาสามารถคอมไพเลอร์ Slava 'switch () ทำงานได้อย่างมีประสิทธิภาพ
วิธีแก้ปัญหา / วิธีแก้ปัญหานี้คือทำอีกวิธีหนึ่ง: ให้คลาส / โครงสร้างของคุณเป็นสมาชิกอาร์เรย์และเขียนฟังก์ชัน accessor เพื่อแนบชื่อกับองค์ประกอบเฉพาะ
struct array_data
{
  int arr[3];
  int &operator[]( unsigned idx ) {
      // assert(idx <= 2);
      //idx = (idx > 2) ? 2 : idx;
      return arr[idx];
  }
  int &a(){ return arr[0]; } // TODO: const versions
  int &b(){ return arr[1]; }
  int &c(){ return arr[2]; }
};
เราสามารถดูได้ที่การส่งออก asm ที่แตกต่างกันสำหรับการใช้งานในกรณีเกี่ยวกับคอมไพเลอร์สำรวจ Godbolt นี่คือฟังก์ชัน x86-64 System V ที่สมบูรณ์โดยละเว้นคำสั่ง RET ต่อท้ายเพื่อแสดงสิ่งที่คุณจะได้รับเมื่ออยู่ในบรรทัด ARM / MIPS / อะไรก็ได้ที่คล้ายกัน
# asm from g++6.2 -O3
int getb(array_data &d) { return d.b(); }
    mov     eax, DWORD PTR [rdi+4]
void setc(array_data &d, int val) { d.c() = val; }
    mov     DWORD PTR [rdi+8], esi
int getidx(array_data &d, int idx) { return d[idx]; }
    mov     esi, esi                   # zero-extend to 64-bit
    mov     eax, DWORD PTR [rdi+rsi*4]
จากการเปรียบเทียบคำตอบของ @ Slava โดยใช้ a switch()สำหรับ C ++ ทำให้ asm เป็นเช่นนี้สำหรับดัชนีตัวแปรรันไทม์ (รหัสในลิงค์ Godbolt ก่อนหน้านี้)
int cpp(data *d, int idx) {
    return (*d)[idx];
}
    # gcc6.2 -O3, using `default: __builtin_unreachable()` to promise the compiler that idx=0..2,
    # avoiding an extra cmov for idx=min(idx,2), or an extra branch to a throw, or whatever
    cmp     esi, 1
    je      .L6
    cmp     esi, 2
    je      .L7
    mov     eax, DWORD PTR [rdi]
    ret
.L6:
    mov     eax, DWORD PTR [rdi+4]
    ret
.L7:
    mov     eax, DWORD PTR [rdi+8]
    ret
เห็นได้ชัดว่าแย่มากเมื่อเทียบกับรุ่นการตีด้วยยูเนี่ยน C (หรือ GNU C ++):
c(type_t*, int):
    movsx   rsi, esi                   # sign-extend this time, since I didn't change idx to unsigned here
    mov     eax, DWORD PTR [rdi+rsi*4]