เหตุใด C ++ จึงไม่อนุญาตโครงสร้างที่ไม่ระบุตัวตน


93

คอมไพเลอร์ C ++ บางตัวอนุญาตให้ใช้สหภาพและโครงสร้างที่ไม่ระบุชื่อเป็นส่วนขยายของ C ++ มาตรฐาน มันเป็นน้ำตาลที่มีประโยชน์มากในบางครั้ง

อะไรคือเหตุผลที่ป้องกันไม่ให้สิ่งนี้เป็นส่วนหนึ่งของมาตรฐาน? มี Roadblock ทางเทคนิคหรือไม่? ปรัชญา? หรือแค่ไม่เพียงพอที่จะต้องพิสูจน์?

นี่คือตัวอย่างของสิ่งที่ฉันกำลังพูดถึง:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

คอมไพเลอร์ของฉันจะยอมรับเรื่องนี้ แต่ก็เตือนว่า"นิรนาม struct / ยูเนี่ยน" เป็นส่วนขยายที่ไม่ได้มาตรฐานที่ C


3
เห็นได้ชัดว่ามีความสับสนเกี่ยวกับความหมายของคุณ คุณช่วยยกตัวอย่างโค้ดที่คอมไพล์เนื่องจากส่วนขยายคอมไพเลอร์ได้ไหม
Rob Kennedy

75
แจ้งให้ทราบว่ามีสองแนวคิดเสียงที่คล้ายกัน แต่มีความแตกต่างกันอย่างมากมาย: structs ชื่อและstructs ที่ไม่ระบุชื่อ อย่างแรกคือสิ่งนี้ซึ่ง C ++ รองรับ: struct { int i; } a; a.i = 0;(ประเภทไม่มีชื่อ) ประการที่สองคือสิ่งนี้ซึ่ง C ++ ไม่รองรับ: struct { int i; }; i = 0;(ประเภทนี้ไม่มีชื่อและหลุดเข้าไปในขอบเขตโดยรอบ) C ++ แต่ไม่สนับสนุนทั้งชื่อและที่ไม่ระบุชื่อสหภาพแรงงาน
Johannes Schaub - litb

ดูเหมือนว่าไลบรารีเวกเตอร์ VMMLib ที่ค่อนข้างน่าสนใจ ฉันเชื่อว่าปัญหาคือสหภาพมีโครงสร้างที่ไม่มีชื่อ แต่ฉันไม่แน่ใจ
greyfade

1
FWIW มัน "ไม่มีชื่อ" ไม่ใช่ "ไม่มีชื่อ" และสหภาพแรงงานได้รับการสนับสนุนตามที่ litb กล่าว stackoverflow.com/q/14248044/560648
Lightness Races in Orbit

1
@AdrianMcCarthy: ไม่เป็นไร (FSVO "ดี" คอมไพเลอร์ที่น่ารำคาญเป็นความลับ) แต่ "ไม่มีชื่อ" เป็นแนวคิดมาตรฐานที่ไม่เกี่ยวข้องกัน
Lightness Races ใน Orbit

คำตอบ:


50

เนื่องจากคนอื่น ๆ ได้ชี้ให้เห็นว่าสหภาพที่ไม่ระบุตัวตนได้รับอนุญาตใน C ++ มาตรฐาน แต่โครงสร้างที่ไม่ระบุตัวตนไม่ได้รับอนุญาต

เหตุผลนี้ก็คือ C สนับสนุนสหภาพที่ไม่ระบุตัวตน แต่ไม่ใช่โครงสร้างแบบไม่ระบุชื่อ * ดังนั้น C ++ จึงสนับสนุนแบบเดิมสำหรับความเข้ากันได้ แต่ไม่ใช่อย่างหลังเนื่องจากไม่จำเป็นสำหรับความเข้ากันได้

นอกจากนี้โครงสร้างที่ไม่ระบุตัวตนใน C ++ ยังไม่มีประโยชน์มากนัก การใช้งานที่แสดงให้เห็นถึงคุณจะมีโครงสร้างที่มีสามลอยซึ่งสามารถเรียกทั้งโดย.v[i]หรือ.x, .yและ.zผมเชื่อว่าผลในพฤติกรรมที่ไม่ได้กำหนดใน C ++ C ++ ไม่อนุญาตให้คุณที่จะเขียนถึงหนึ่งในสมาชิกของสหภาพการพูดแล้วอ่านจากสมาชิกอีกคนหนึ่งกล่าวว่า.v[1] .yแม้ว่าโค้ดที่ทำเช่นนี้จะไม่ใช่เรื่องแปลก แต่ก็ไม่ได้กำหนดไว้อย่างชัดเจน

สิ่งอำนวยความสะดวกของ C ++ สำหรับประเภทที่ผู้ใช้กำหนดเองให้โซลูชันทางเลือก ตัวอย่างเช่น:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11 เห็นได้ชัดว่าเพิ่มโครงสร้างที่ไม่ระบุตัวตนดังนั้นการแก้ไข C ++ ในอนาคตอาจเพิ่มได้


2
+1: ตัวอย่างของฉันอาศัยพฤติกรรมที่ไม่ได้กำหนดไว้ใน C ++ ซึ่งเป็นสิ่งที่ฉันไม่ได้ตระหนักถึงเมื่อฉันเขียนคำถาม
Adrian McCarthy

2
"C ++ ไม่อนุญาตให้คุณเขียนถึงสมาชิกคนหนึ่งของสหภาพ [... ] แล้วอ่านจากสมาชิกคนอื่น" - เว้นแต่ว่าสมาชิกจะเป็นวัตถุโครงร่างมาตรฐานและแบ่งปันลำดับเริ่มต้นทั่วไปของสมาชิกของพวกเขาเองและคุณ เขียนใหม่ / การอ่านของพวกเขาสมาชิกภายในลำดับเริ่มต้นกล่าวว่าที่พบบ่อย ที่จะได้รับอนุญาต (เช่นกำหนด)
underscore_d

5
@underscore_d: ใช่หากประเภทเป็นรูปแบบมาตรฐานที่มีลำดับเริ่มต้นทั่วไป อย่างไรก็ตามโครงสร้างไม่สามารถใช้แทนอาร์เรย์ด้วยวิธีนี้ได้เนื่องจากกฎ "ลำดับเริ่มต้นทั่วไป" ของ C ++ ระบุว่าลำดับเริ่มต้นทั่วไปจะอยู่ระหว่างโครงสร้างเท่านั้น ไม่ได้กล่าวถึงอาร์เรย์ดังนั้นจึงไม่สามารถใช้นามแฝงเช่นนี้ได้
Nicol Bolas

@NicolBolas โอ้ฮ่าฮ่า - เชื่อฉันสิ - ฉันหวังว่าหลายครั้งที่อาร์เรย์และสิ่งดั้งเดิมอื่น ๆ รวมอยู่ในค่าเผื่อนี้! แต่ฉันไม่ได้คิดมากเกี่ยวกับข้อ จำกัด ในทางปฏิบัติที่เป็นไปได้ดังนั้นอาจจะไม่ง่ายอย่างที่คิดในปัจจุบัน ความคิดเห็นของฉันกว้างขึ้น แต่อาจมีความเสี่ยงโดยนัยว่าฉันคิดว่าอาร์เรย์รวมอยู่ในสิ่งนี้ดังนั้นขอขอบคุณที่เพิ่มเข้ามา
underscore_d

"เหตุผลนี้คือ C สนับสนุนสหภาพที่ไม่ระบุชื่อ แต่ไม่ระบุโครงสร้าง" - ไม่ใช่เชิงอรรถของคุณชี้แจงว่าคุณกำลังพูดถึง C99 หรือก่อนหน้านี้ที่นี่ คำว่า "สหภาพนิรนาม" ไม่ปรากฏที่ใดในมาตรฐาน C99 GCC อ้างในการวินิจฉัย (ด้วย -std = c99 - ตัวเลือกฐานทัพ) ว่า "ISO C99 ไม่รองรับโครงสร้าง / สหภาพที่ไม่มีชื่อ" มาตรฐานไม่ได้กล่าวถึงสิ่งใดเกี่ยวกับสมาชิกที่ไม่มีชื่อนอกเหนือจากบิตฟิลด์ที่ไม่มีชื่อ ฉันไม่แน่ใจทั้งหมดว่าการประกาศโครงสร้างเป็นการประกาศหรือไม่ แต่ถ้าเป็นเช่นนั้นสหภาพที่ไม่ระบุชื่อถือเป็นการละเมิดข้อ จำกัด ต่อ 6.7p2 โดยที่ไม่ได้กำหนดไว้อย่างดีที่สุด

21

ฉันจะบอกว่าคุณสามารถล้างvector3คำประกาศของคุณได้โดยใช้ไฟล์union

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

แน่นอนว่าโครงสร้างที่ไม่ระบุชื่อเป็นส่วนขยาย MSVC แต่ ISO C11 อนุญาตตอนนี้และgcc อนุญาตและคอมไพเลอร์ llvm ของ Apple ก็เช่นกัน

ทำไมใน C11 ถึงไม่ใช่ C ++ 11 ฉันไม่แน่ใจ แต่ในทางปฏิบัติส่วนใหญ่ (gcc ++, MSVC ++ และคอมไพเลอร์ C ++ ของ Apple) คอมไพเลอร์ C ++ รองรับ


1
+1 สำหรับข้อมูลที่อัปเดต เหตุผลที่ฉันมีโครงสร้างภายนอกก็เพราะ "รหัสจริง" มีวิธีการเช่นกัน
Adrian McCarthy

สิ่งเดียวที่คุณไม่สามารถทำกับสหภาพให้มีสมาชิกข้อมูลคงที่หรือการใช้มรดก
bobobobo

2
ขอบคุณ. ฉันไม่เคยใช้สหภาพใหม่เหมือนโครงสร้างหรือคลาส
Adrian McCarthy

ฉันรู้ว่า Sun studio ไม่รองรับโครงสร้างแบบไม่ระบุตัวตนก่อน C ++ 11 โดยค่าเริ่มต้น หากคุณกำลังเขียนโค้ดข้ามแพลตฟอร์มและคอมไพเลอร์ไม่ได้รับการอัปเกรดเป็น C + 11 อย่าใช้โครงสร้างแบบไม่ระบุตัวตน
irsis

6

ไม่แน่ใจคุณหมายถึงอะไร. ส่วนที่ 9.5 ของข้อมูลจำเพาะ C ++ ข้อ 2:

การรวมกันของแบบฟอร์ม

union { member-specification } ;

เรียกว่าสหภาพนิรนาม กำหนดวัตถุที่ไม่มีชื่อของประเภทที่ไม่มีชื่อ

คุณสามารถทำสิ่งนี้ได้เช่นกัน:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

ไม่มีประโยชน์เสมอไป ... แม้ว่าบางครั้งจะมีประโยชน์ในคำจำกัดความมาโครที่น่ารังเกียจ


11
-1 เพราะมันบอกว่ามันกำหนดโครงสร้างที่ไม่ระบุตัวตน ดูความคิดเห็นด้านบนของคำถาม - คุณกำลังกำหนดโครงสร้างที่ไม่มีชื่อไม่ใช่แบบไม่ระบุชื่อ
Johannes Schaub - litb

1

สหภาพแรงงานสามารถไม่ระบุชื่อ ดูมาตรฐาน 9.5 ย่อหน้า 2

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


1

จากการแก้ไขความคิดเห็นและบทความ MSDN นี้: Anonymous Structuresฉันจะคาดเดาได้ยาก - มันเข้ากันได้ไม่ดีกับแนวคิดของการห่อหุ้ม ฉันคงไม่คิดว่าสมาชิกคนหนึ่งของชั้นเรียนจะยุ่งกับเนมสเปซชั้นเรียนของฉันนอกจากเพิ่มสมาชิกเพียงคนเดียว นอกจากนี้การเปลี่ยนแปลงโครงสร้างแบบไม่ระบุตัวตนอาจส่งผลต่อคลาสของฉันโดยไม่ได้รับอนุญาต


1
เนื่องจากวิธีการสร้างโครงสร้าง / สหภาพที่ไม่ระบุชื่อ (เป็นแบบพิเศษไวยากรณ์แบบอินไลน์ที่ไม่สามารถซ่อนได้ยกเว้นโดยมาโคร) คุณจึงไม่แปลกใจเลยที่สมาชิกบางคนที่คุณใช้เป็นสมาชิกที่ไม่ระบุชื่อ ดังนั้นฉันไม่คิดว่าเหตุผลนี้จะสมเหตุสมผล สาเหตุที่แท้จริงคือสหภาพที่ไม่ระบุชื่อได้รับการสนับสนุนใน C ++ สำหรับความเข้ากันได้ของ C เท่านั้น C ไม่สนับสนุนโครงสร้างที่ไม่ระบุตัวตน (จนถึง C11) ดังนั้น C ++ จึงไม่รองรับเช่นกัน
bames53

1

รหัสของคุณ

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

ก็เหมือน

union Foo {
   int;
   float v[3];
};

ซึ่งไม่ถูกต้องแน่นอน (ใน C99 และก่อนหน้านี้)

เหตุผลน่าจะเพื่อลดความซับซ้อนของการแยกวิเคราะห์ (ใน C) เนื่องจากในกรณีนี้คุณจะต้องตรวจสอบว่าโครงสร้าง / สหภาพแรงงานมีเพียง "คำสั่งผู้ประกาศ" เช่น

Type field;

ที่กล่าวว่าgcc และ "คอมไพเลอร์อื่น ๆ "สนับสนุนฟิลด์ที่ไม่มีชื่อเป็นส่วนขยาย

แก้ไข:ขณะนี้โครงสร้างที่ไม่ระบุชื่อได้รับการสนับสนุนอย่างเป็นทางการใน C11 (§6.7.2.1 / 13)


5
จากมุมมองของการแยกฉันไม่คิดว่าunion { ... }มีความแตกต่างใด ๆ struct { ... }มากกว่า อดีตใช้ได้ แต่หลังไม่ได้
Johannes Schaub - litb

3
เมื่อพิจารณาถึงความยากลำบากอย่างไร้เหตุผลในการแยกวิเคราะห์โดยทั่วไปของ C ++ ฉันสงสัยว่ามาตรฐานกำหนดโครงสร้างและสหภาพที่ไม่ได้รับอนุญาตที่ไม่ได้รับอนุญาตเพียงเพื่อให้การแยกวิเคราะห์ง่ายขึ้น
Adrian McCarthy

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

@ เอเดรียนจุดดีที่นั่นเอเดรียนฉันไม่เคยคิดว่า "ยากเกินไปที่จะใช้" จะเป็นความกังวลของ Bjarne และทีมงาน
bobobobo

C และ C ++ สนับสนุนสหภาพที่ไม่มีชื่อดังนั้นความคิดเห็นที่union { ... };ไม่ถูกต้องจึงไม่ถูกต้อง
bames53
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.