ทำไมคุณใช้ typedef เมื่อประกาศ enum ใน C ++


183

ฉันยังไม่ได้เขียน C ++ ในเวลาหลายปีและตอนนี้ฉันกำลังพยายามกลับเข้าไป จากนั้นฉันก็วิ่งข้ามสิ่งนี้และคิดเกี่ยวกับการยอมแพ้:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

นี่คืออะไร? เหตุใดจึงtypedefใช้คำหลักที่นี่ เหตุใดชื่อจึงTokenTypeปรากฏขึ้นสองครั้งในการประกาศนี้ ความหมายต่างจากนี้อย่างไร

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

คำตอบ:


156

ใน C การประกาศ enum ของคุณด้วยวิธีแรกช่วยให้คุณใช้มันได้เช่น:

TokenType my_type;

หากคุณใช้รูปแบบที่สองคุณจะถูกบังคับให้ประกาศตัวแปรของคุณเช่นนี้:

enum TokenType my_type;

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


12
คำถามของคุณถูกต้องเฉพาะกับ C แต่ไม่ใช่ C ++ ใน C ++ enums และ structs สามารถใช้ได้โดยตรงราวกับว่ามี typedef
David Rodríguez - dribeas

7
ใช่ แต่นี่จะตอบคำถามจริงที่ถามซึ่งเกี่ยวกับ "สิ่งนี้หมายถึงอะไร?"
BobbyShaftoe

ดังนั้นเทคนิคนี้เป็น typedef หรือ enum หรือไม่?
Miek

5
มันทั้งคู่ คุณอาจพูดได้ว่า: enum TokenType_ {... }; typedef enum TokenType_ TokenType;
Ryan Fox

คำตอบนั้นสมบูรณ์ แต่ฉันเชื่อว่าประเด็นคือ TokenType; หลังจากการประกาศ enum คือสิ่งที่ประกาศชื่อประเภท ดังนั้นคำตอบนั้นไม่สมบูรณ์ 100% การประกาศ 'วิธีแรก' ระบุทั้ง enum และ typename ใหม่ที่ enum นั้นในหนึ่งหยดของไวยากรณ์ ดังนั้นคำตอบก็มีประโยชน์ แต่ฉันคิดว่าควรปรับปรุงเล็กน้อย บางทีฉันรุนแรงเกินไปที่จะลงคะแนน ดังนั้นฉันจึงลงคะแนนหลังจากนั้น ถ้าฉันแน่ใจในตัวเองจริงๆฉันจะขอย้อยเวลาแก้ไข / ปรับปรุงคำตอบ ... แต่นี่เป็นคำตอบที่ดีทีเดียว
Ross Youngblood

97

มันเป็นมรดก C ใน C ถ้าคุณทำ:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

คุณจะต้องใช้มันทำสิ่งที่ชอบ:

enum TokenType foo;

แต่ถ้าคุณทำสิ่งนี้:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

คุณจะสามารถประกาศ:

TokenType foo;

แต่ใน C ++ คุณสามารถใช้นิยามเดิมเท่านั้นและใช้มันเหมือนกับว่ามันอยู่ใน C typedef


1
สิ่งที่คุณพูดนั้นจริงใน C มันไม่จริงใน C ++
Jonathan Leffler

49
ไม่ใช่สิ่งที่ฉันพูดในประโยคสุดท้ายของฉัน
เสื่อ

2
@mat ฉันยกระดับความคิดเห็นของคุณเกี่ยวกับประโยคสุดท้าย แต่เพื่อความเป็นธรรมมันเป็นคำพูดที่ไม่ดีและสับสน
AR

20

คุณไม่จำเป็นต้องทำ ใน C (ไม่ใช่ C ++) คุณจำเป็นต้องใช้Enum Enumnameเพื่ออ้างถึงองค์ประกอบข้อมูลของชนิดข้อมูลที่ระบุ เพื่อลดความซับซ้อนมันคุณได้รับอนุญาตให้typedefมันเป็นชื่อเดียวชนิดข้อมูล

typedef enum MyEnum { 
  //...
} MyEnum;

ฟังก์ชันที่อนุญาตให้ใช้พารามิเตอร์ของ enum เพื่อกำหนดเป็น

void f( MyEnum x )

แทนอีกต่อไป

void f( enum MyEnum x )

โปรดทราบว่าชื่อของ typename ไม่จำเป็นต้องเท่ากับชื่อของ enum เช่นเดียวกับ structs

ใน C ++ ในทางกลับกันมันไม่จำเป็นเนื่องจาก enums คลาสและ structs สามารถเข้าถึงได้โดยตรงตามชนิดของชื่อ

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

ที่จริงฉันคิดว่านี่อาจเป็นคำตอบที่ดีกว่าคำตอบที่ยอมรับกันโดยทั่วไปเพราะมันอธิบายอย่างชัดเจนว่า "ทำไม" มันแตกต่างกัน
Ross Youngblood

11

ใน C มันเป็นสไตล์ที่ดีเพราะคุณสามารถเปลี่ยนประเภทเป็นอะไรที่นอกเหนือจาก enum

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

ใน C ++ คุณสามารถกำหนด enum เพื่อให้คอมไพล์เป็น C ++ หรือ C


คุณไม่ได้หมายความว่าจะพูดIn C++ you can *typedef* the enum so that it will compile as C++ or C.? คุณบอกว่า: In C++ you can define the enum so that it will compile as C++ or C.แจ้งให้ทราบว่าผมเปลี่ยนของคุณจะdefine typedefดี ... ฉันคิดว่าtypedefไอเอ็นจีกำลังกำหนด
Gabriel Staples

6

โฮลด์จาก C.


Dunno ว่าตัวเลือก 'เร็ว' มีความเกี่ยวข้อง คุณยังคงเขียนไว้ใน C หากคุณต้องการใช้ชื่อประเภทโดยไม่มีคำนำหน้า enum
Jonathan Leffler

1
จริง ฉันจะลบมัน ฉันไม่ได้ปฏิบัติตามข้อกำหนด C เป็นเวลานาน ฉันขี้เกียจเกินไปที่จะตรวจสอบความแตกต่างของ c / c ++ ... -1 สำหรับฉัน
ทิม

6

บางคนบอกว่า C ไม่มีเนมสเปซ แต่ไม่ถูกต้องทางเทคนิค มันมีสาม:

  1. แท็ก ( enum, unionและstruct)
  2. ป้ายกำกับ
  3. (อย่างอื่น)

typedef enum { } XYZ;ประกาศการแจงนับไม่ระบุชื่อและการนำเข้ามันเข้าไปใน namespace XYZโลกที่มีชื่อ

typedef enum ABC { } XYZ;ประกาศ enum ชื่อABCใน namespace แท็กแล้วนำเข้าลงใน namespace XYZโลกเป็น

บางคนไม่ต้องการรำคาญกับเนมสเปซที่แยกต่างหากดังนั้นพวกเขาจึงพิมพ์ทุกอย่าง คนอื่น ๆ ไม่เคยพิมพ์เพราะพวกเขาต้องการการกำหนดชื่อ


มันไม่ถูกต้อง structs, unions และ enums อ้างอิงโดยชื่อแท็ก (เว้นแต่จะไม่ระบุตัวตนตามที่คุณพูดถึง) มีเนมสเปซแยกต่างหากสำหรับประเภทและแท็ก คุณสามารถมีประเภทที่มีชื่อเดียวกันแน่นอนกับแท็กและรวบรวมปรับ อย่างไรก็ตามถ้า enum มีแท็กเดียวกันกับ struct นี่เป็นข้อผิดพลาดในการคอมไพล์เหมือนกับ 2 structs หรือ 2 enums ที่มีแท็กเดียวกันจะเป็น การลืมว่าป้ายกำกับสำหรับข้ามไปเป็นเนมสเปซแยกต่างหาก ป้ายกำกับอาจเป็นชื่อเดียวกับแท็กหรือตัวระบุ แต่ไม่ใช่ประเภทและตัวระบุสามารถมีชื่อเดียวกับแท็ก แต่ไม่ใช่ประเภท
Rich Jahn

3

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

นี่มันเป็น ฉันควรอ้างอิงคำอธิบายที่อยู่ในใจเสมอเมื่อฉันต้องเข้าใจ typedefs ที่น่ารังเกียจ:

ในการประกาศตัวแปรชื่อที่แนะนำคืออินสแตนซ์ของประเภทที่เกี่ยวข้อง [... ] อย่างไรก็ตามเมื่อtypedefคำหลักนำหน้าการประกาศชื่อที่แนะนำจะเป็นชื่อแทนของประเภทที่เกี่ยวข้อง

ขณะที่หลายคนก่อนหน้านี้กล่าวว่ามีความจำเป็นต้องใช้ typedefs ประกาศ enums ในc ++ แต่นั่นเป็นคำอธิบายของไวยากรณ์ของ typedef! ฉันหวังว่ามันจะช่วยได้ (อาจจะไม่ใช่ OP เพราะมันเกือบ 10 ปีแล้ว แต่ทุกคนที่ดิ้นรนเพื่อทำความเข้าใจกับสิ่งเหล่านี้)


1

ในคู่มือสไตล์โค้ด C บางตัวเวอร์ชัน typedef ได้รับการกล่าวถึงว่าเป็นที่ต้องการสำหรับ "ความชัดเจน" และ "ความเรียบง่าย" ฉันไม่เห็นด้วยเพราะ typedef ทำให้งงธรรมชาติที่แท้จริงของวัตถุที่ประกาศ ที่จริงแล้วฉันไม่ได้ใช้ typedefs เพราะเมื่อประกาศตัวแปร C ฉันต้องการที่จะชัดเจนเกี่ยวกับสิ่งที่วัตถุจริง ตัวเลือกนี้ช่วยให้ฉันจำได้เร็วขึ้นว่าโค้ดเก่าทำอะไรได้จริงและจะช่วยเหลือผู้อื่นเมื่อรักษารหัสไว้ในอนาคต


1

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.