ฉันสงสัยว่าtypedef
และ#define
เหมือนกันในค?
ฉันสงสัยว่าtypedef
และ#define
เหมือนกันในค?
คำตอบ:
เลขที่
#define
เป็นโทเค็นก่อนตัวประมวลผล: ตัวคอมไพเลอร์จะไม่เห็นมัน
typedef
เป็นโทเค็นคอมไพเลอร์: ตัวประมวลผลล่วงหน้าไม่สนใจมัน
คุณสามารถใช้อย่างใดอย่างหนึ่งเพื่อให้ได้เอฟเฟกต์เดียวกัน แต่จะดีกว่าถ้าใช้อย่างเหมาะสมกับความต้องการของคุณ
#define MY_TYPE int
typedef int My_Type;
เมื่อสิ่งต่างๆ "ขน" การใช้เครื่องมือที่เหมาะสมจะทำให้ถูกต้อง
#define FX_TYPE void (*)(int)
typedef void (*stdfx)(int);
void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
void fx_def(void (*)(int) fx);
; void fx_def(void (*fx)(int));
ประกาศที่ถูกต้องคือ
#define FX_TYPE(f) void (*f)(int)
คำแนะนำการทำงานเป็นไปได้ที่มีแมโครเท่านั้นหากคุณพร้อมที่จะให้ขึ้นไวยากรณ์: จากนั้นคุณจะประกาศฟังก์ชันของคุณเป็น:void fx_def(FX_TYPE(fx));
typedef
ปฏิบัติตามกฎการกำหนดขอบเขตเช่นเดียวกับตัวแปรในขณะที่define
ยังคงใช้ได้จนกว่าจะสิ้นสุดหน่วยการคอมไพล์ (หรือจนกว่าจะมีการจับคู่undef
)
นอกจากนี้ยังมีบางสิ่งบางอย่างที่สามารถทำได้ด้วยที่ไม่สามารถทำได้ด้วยtypedef
ตัวอย่างเช่น:define
typedef int* int_p1;
int_p1 a, b, c; // a, b, c are all int pointers
#define int_p2 int*
int_p2 a, b, c; // only the first is a pointer, because int_p2
// is replaced with int*, producing: int* a, b, c
// which should be read as: int *a, b, c
typedef int a10[10];
a10 a, b, c; // create three 10-int arrays
typedef int (*func_p) (int);
func_p fp; // func_p is a pointer to a function that
// takes an int and returns an int
ไม่พวกเขาไม่เหมือนกัน ตัวอย่างเช่น:
#define INTPTR int*
...
INTPTR a, b;
หลังจากการประมวลผลล่วงหน้าบรรทัดนั้นจะขยายเป็น
int* a, b;
หวังว่าคุณจะเห็นปัญหา เพียง แต่a
จะมีชนิดint *
; b
จะถูกประกาศว่าเป็นแบบธรรมดาint
(เนื่องจาก*
มีความเกี่ยวข้องกับผู้ประกาศไม่ใช่ตัวระบุประเภท)
ตรงกันข้ามกับ
typedef int *INTPTR;
...
INTPTR a, b;
ในกรณีนี้ทั้งสองa
และจะมีประเภท b
int *
มี typedef ทั้งคลาสที่ไม่สามารถจำลองด้วยมาโครตัวประมวลผลล่วงหน้าเช่นพอยน์เตอร์ไปยังฟังก์ชันหรืออาร์เรย์:
typedef int (*CALLBACK)(void);
typedef int *(*(*OBNOXIOUSFUNC)(void))[20];
...
CALLBACK aCallbackFunc; // aCallbackFunc is a pointer to a function
// returning int
OBNOXIOUSFUNC anObnoxiousFunc; // anObnoxiousFunc is a pointer to a function
// returning a pointer to a 20-element array
// of pointers to int
ลองใช้มาโครตัวประมวลผลล่วงหน้า
#defineกำหนดมาโคร
typedefกำหนดประเภท
ตอนนี้บอกว่านี่คือความแตกต่างเล็กน้อย:
ด้วย#defineคุณสามารถกำหนดค่าคงที่ที่สามารถใช้ในเวลาคอมไพล์ได้ ค่าคงที่สามารถใช้กับ#ifdefเพื่อตรวจสอบว่าโค้ดถูกคอมไพล์อย่างไรและเชี่ยวชาญโค้ดบางอย่างตามพารามิเตอร์คอมไพล์
คุณยังสามารถใช้#defineเพื่อประกาศฟังก์ชันแมโครขนาดเล็กค้นหาและแทนที่ได้
typedefสามารถใช้เพื่อกำหนดนามแฝงให้กับประเภท (ซึ่งคุณอาจทำได้ด้วย#defineเช่นกัน) แต่จะปลอดภัยกว่าเนื่องจากลักษณะการค้นหาและแทนที่ของค่าคงที่#define
นอกจากนั้นคุณสามารถใช้การประกาศไปข้างหน้าด้วยtypedefซึ่งช่วยให้คุณสามารถประกาศประเภทที่จะใช้ แต่ยังไม่ได้เชื่อมโยงกับไฟล์ที่คุณกำลังเขียนอยู่
มาโครตัวประมวลผลล่วงหน้า (" #define
's") เป็นเครื่องมือทดแทนคำศัพท์ a la "search and replace" พวกเขาไม่เชื่อเรื่องพระเจ้าในภาษาโปรแกรมและไม่เข้าใจว่าคุณกำลังพยายามทำอะไรอยู่ คุณอาจคิดว่าพวกเขาเป็นช่างคัดลอก / วางที่ได้รับการยกย่องซึ่งบางครั้งก็มีประโยชน์ แต่คุณควรใช้ด้วยความระมัดระวัง
Typedefs เป็นคุณลักษณะภาษาซีที่ให้คุณสร้างนามแฝงสำหรับประเภทต่างๆ สิ่งนี้มีประโยชน์อย่างยิ่งในการสร้างชนิดของสารประกอบที่ซับซ้อน (เช่นโครงสร้างและตัวชี้ฟังก์ชัน) ที่อ่านได้และจัดการได้ (ใน C ++ ยังมีสถานการณ์ที่คุณต้องพิมพ์ประเภท)
สำหรับ (3): คุณควรเลือกใช้ฟีเจอร์ภาษามากกว่ามาโครตัวประมวลผลล่วงหน้าเมื่อเป็นไปได้! ดังนั้นควรใช้ typedef สำหรับประเภทและค่าคงที่สำหรับค่าคงที่เสมอ ด้วยวิธีนี้คอมไพเลอร์สามารถโต้ตอบกับคุณได้อย่างมีความหมาย โปรดจำไว้ว่าคอมไพเลอร์เป็นเพื่อนของคุณดังนั้นคุณควรบอกให้มากที่สุด มาโครตัวประมวลผลล่วงหน้าทำตรงกันข้ามโดยซ่อนความหมายของคุณจากคอมไพเลอร์
มีความแตกต่างกันมากแม้ว่ามักจะใช้ในการใช้ประเภทข้อมูลที่กำหนดเอง (ซึ่งเป็นสิ่งที่ฉันคิดว่าคำถามนี้เป็นข้อมูลเกี่ยวกับ)
ดังที่กล่าวถึง pmg #define
จะถูกจัดการโดยตัวประมวลผลล่วงหน้า (เช่นการดำเนินการตัดและวาง) ก่อนที่คอมไพเลอร์จะเห็นโค้ดและtypedef
ถูกแปลโดยคอมไพลเลอร์
ความแตกต่างหลักอย่างหนึ่ง (อย่างน้อยก็ในการกำหนดชนิดข้อมูล) คือtypedef
ช่วยให้สามารถตรวจสอบประเภทที่เฉพาะเจาะจงมากขึ้น ตัวอย่างเช่น,
#define defType int
typedef int tdType
defType x;
tdType y;
ที่นี่คอมไพเลอร์มองว่าตัวแปร x เป็น int แต่ตัวแปร y เป็นชนิดข้อมูลที่เรียกว่า 'tdType' ที่มีขนาดเท่ากับ int หากคุณเขียนฟังก์ชันที่รับพารามิเตอร์ประเภท defType ผู้เรียกสามารถส่งผ่าน int ปกติและคอมไพเลอร์จะไม่ทราบความแตกต่าง หากฟังก์ชันใช้พารามิเตอร์ประเภท tdType แทนคอมไพลเลอร์จะตรวจสอบให้แน่ใจว่ามีการใช้ตัวแปรประเภทที่เหมาะสมระหว่างการเรียกใช้ฟังก์ชัน
นอกจากนี้ยังมีจุดบกพร่องบางคนมีความสามารถในการจับtypedef
s ซึ่งอาจจะเป็นประโยชน์มากขึ้นกว่าที่มีประเภทที่กำหนดเองทั้งหมดระบุว่าเป็นชนิดดั้งเดิมพื้นฐานของพวกเขา (มันจะเป็นถ้า#define
ถูกนำมาใช้แทน)
ไม่ใช่
typedefเป็นคีย์เวิร์ด C ที่สร้างนามแฝงสำหรับประเภท
#define เป็นคำสั่งก่อนตัวประมวลผลที่สร้างเหตุการณ์การแทนที่ข้อความก่อนการคอมไพล์ เมื่อคอมไพเลอร์เข้าสู่โค้ดคำ "#defined" ดั้งเดิมจะไม่มีอีกต่อไป #define ส่วนใหญ่จะใช้สำหรับมาโครและค่าคงที่ทั่วโลก
AFAIK เลขที่
typedef
ช่วยคุณตั้งค่า "นามแฝง" ให้กับประเภทข้อมูลที่มีอยู่ สำหรับเช่น typedef char chr
;
#define
เป็นคำสั่งพรีโปรเซสเซอร์ที่ใช้ในการกำหนดมาโครหรือการแทนที่รูปแบบทั่วไป สำหรับเช่น #define MAX 100
แทนที่เหตุการณ์ทั้งหมดMAX
ด้วย 100
ดังที่ได้กล่าวมาแล้วมีความแตกต่างที่สำคัญระหว่าง#define
และ typedef วิธีคิดที่ถูกต้องคือการดู typedef ว่าเป็นประเภท "encapsulated" ที่สมบูรณ์ หมายความว่าคุณไม่สามารถเพิ่มเข้าไปได้หลังจากที่คุณประกาศไปแล้ว
คุณสามารถขยายชื่อประเภทมาโครด้วยตัวระบุประเภทอื่น ๆ ได้ แต่ไม่ใช่ชื่อประเภทที่พิมพ์
#define fruit int
unsigned fruit i; // works fine
typedef int fruit;
unsigned fruit i; // illegal
นอกจากนี้ชื่อ typedef ยังระบุประเภทสำหรับตัวปฏิเสธทุกตัวในการประกาศ
#define fruit int *
fruit apple, banana;
หลังจากการขยายมาโครบรรทัดที่สองจะกลายเป็น:
int *apple, banana;
Apple เป็นตัวชี้ไปที่ int ในขณะที่ banana เป็น int ในการเปรียบเทียบ. typedef เช่นนี้:
typedef char *fruit;
fruit apple, banana;
ประกาศว่าทั้งแอปเปิ้ลและกล้วยเหมือนกัน ชื่อที่อยู่ด้านหน้าแตกต่างกัน แต่ทั้งคู่เป็นตัวชี้ไปยังถ่าน
อย่างที่ทุกคนกล่าวไว้ข้างต้นไม่เหมือนกัน ส่วนใหญ่ของคำตอบที่ระบุจะเป็นประโยชน์มากกว่าtypedef
#define
แต่ให้ฉันใส่จุดบวกของ#define
:
เมื่อรหัสของคุณมีขนาดใหญ่มากกระจายอยู่ทั่วไฟล์จำนวนมากจะดีกว่าที่จะใช้#define
; ช่วยในการอ่านง่าย - คุณสามารถประมวลผลโค้ดทั้งหมดล่วงหน้าเพื่อดูนิยามประเภทที่แท้จริงของตัวแปรที่ตำแหน่งของการประกาศนั้นเอง
stdfx
อ็อบเจ็กต์ที่ถูกต้องของชนิดนั้นคือพอยน์เตอร์ไปยังฟังก์ชันที่ได้รับ int และไม่ส่งคืนค่า