typedef และ #define เหมือนกันใน c หรือไม่


คำตอบ:


122

เลขที่

#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 */

3
หลังจาก typedef stdfxอ็อบเจ็กต์ที่ถูกต้องของชนิดนั้นคือพอยน์เตอร์ไปยังฟังก์ชันที่ได้รับ int และไม่ส่งคืนค่า
58

1
เหตุใด #define จึงล้มเหลวใน casec of function pointer เป็นอาร์กิวเมนต์
Allahjane

2
@Allahjane: การขยายตัวจะกลายเป็นvoid fx_def(void (*)(int) fx);; void fx_def(void (*fx)(int));ประกาศที่ถูกต้องคือ
pmg

5
#define FX_TYPE(f) void (*f)(int)คำแนะนำการทำงานเป็นไปได้ที่มีแมโครเท่านั้นหากคุณพร้อมที่จะให้ขึ้นไวยากรณ์: จากนั้นคุณจะประกาศฟังก์ชันของคุณเป็น:void fx_def(FX_TYPE(fx));
plafer

229

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

23

ไม่พวกเขาไม่เหมือนกัน ตัวอย่างเช่น:

#define INTPTR int*
...
INTPTR a, b;

หลังจากการประมวลผลล่วงหน้าบรรทัดนั้นจะขยายเป็น

int* a, b;

หวังว่าคุณจะเห็นปัญหา เพียง แต่aจะมีชนิดint *; bจะถูกประกาศว่าเป็นแบบธรรมดาint(เนื่องจาก*มีความเกี่ยวข้องกับผู้ประกาศไม่ใช่ตัวระบุประเภท)

ตรงกันข้ามกับ

typedef int *INTPTR;
...
INTPTR a, b;

ในกรณีนี้ทั้งสองaและจะมีประเภท bint *

มี 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

ลองใช้มาโครตัวประมวลผลล่วงหน้า


13

#defineกำหนดมาโคร
typedefกำหนดประเภท

ตอนนี้บอกว่านี่คือความแตกต่างเล็กน้อย:

ด้วย#defineคุณสามารถกำหนดค่าคงที่ที่สามารถใช้ในเวลาคอมไพล์ได้ ค่าคงที่สามารถใช้กับ#ifdefเพื่อตรวจสอบว่าโค้ดถูกคอมไพล์อย่างไรและเชี่ยวชาญโค้ดบางอย่างตามพารามิเตอร์คอมไพล์
คุณยังสามารถใช้#defineเพื่อประกาศฟังก์ชันแมโครขนาดเล็กค้นหาและแทนที่ได้

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


คุณหมายถึงอะไรเมื่อค้นหาและแทนที่ลักษณะของ #define , ขอบคุณ
Mohamed El Shenawy

1
หมายความว่าก่อนการคอมไพล์พรีโปรเซสเซอร์จะค้นหามาโครทั้งหมดและแทนที่ด้วยไวยากรณ์ดั้งเดิม
Prince Vijay Pratap

"typedef สามารถใช้เพื่อตั้งนามแฝงให้กับประเภท" สิ่งนี้อธิบายจุดประสงค์สำหรับฉันขอบคุณ
Dave Voyles

8

มาโครตัวประมวลผลล่วงหน้า (" #define's") เป็นเครื่องมือทดแทนคำศัพท์ a la "search and replace" พวกเขาไม่เชื่อเรื่องพระเจ้าในภาษาโปรแกรมและไม่เข้าใจว่าคุณกำลังพยายามทำอะไรอยู่ คุณอาจคิดว่าพวกเขาเป็นช่างคัดลอก / วางที่ได้รับการยกย่องซึ่งบางครั้งก็มีประโยชน์ แต่คุณควรใช้ด้วยความระมัดระวัง

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

สำหรับ (3): คุณควรเลือกใช้ฟีเจอร์ภาษามากกว่ามาโครตัวประมวลผลล่วงหน้าเมื่อเป็นไปได้! ดังนั้นควรใช้ typedef สำหรับประเภทและค่าคงที่สำหรับค่าคงที่เสมอ ด้วยวิธีนี้คอมไพเลอร์สามารถโต้ตอบกับคุณได้อย่างมีความหมาย โปรดจำไว้ว่าคอมไพเลอร์เป็นเพื่อนของคุณดังนั้นคุณควรบอกให้มากที่สุด มาโครตัวประมวลผลล่วงหน้าทำตรงกันข้ามโดยซ่อนความหมายของคุณจากคอมไพเลอร์


คุณสามารถบอกตัวอย่างหนึ่งใน C ++ ที่คุณต้องพิมพ์เป็นประเภทได้หรือไม่? ฉันแค่อยากรู้เกี่ยวกับเรื่องนั้น
jyz

@jyzuz: มีบางอย่างถ้าคุณต้องการให้ฟังก์ชันสมาชิกส่งคืนอาร์เรย์ของตัวชี้ฟังก์ชันหรืออะไรทำนองนั้น - ถ้าคุณพยายามสะกดประเภท GCC จะพูดว่า "คุณต้องใช้ตัวพิมพ์"
Kerrek SB

4

มีความแตกต่างกันมากแม้ว่ามักจะใช้ในการใช้ประเภทข้อมูลที่กำหนดเอง (ซึ่งเป็นสิ่งที่ฉันคิดว่าคำถามนี้เป็นข้อมูลเกี่ยวกับ)

ดังที่กล่าวถึง pmg #defineจะถูกจัดการโดยตัวประมวลผลล่วงหน้า (เช่นการดำเนินการตัดและวาง) ก่อนที่คอมไพเลอร์จะเห็นโค้ดและtypedefถูกแปลโดยคอมไพลเลอร์

ความแตกต่างหลักอย่างหนึ่ง (อย่างน้อยก็ในการกำหนดชนิดข้อมูล) คือtypedefช่วยให้สามารถตรวจสอบประเภทที่เฉพาะเจาะจงมากขึ้น ตัวอย่างเช่น,

#define defType int
typedef int tdType

defType x;
tdType y;

ที่นี่คอมไพเลอร์มองว่าตัวแปร x เป็น int แต่ตัวแปร y เป็นชนิดข้อมูลที่เรียกว่า 'tdType' ที่มีขนาดเท่ากับ int หากคุณเขียนฟังก์ชันที่รับพารามิเตอร์ประเภท defType ผู้เรียกสามารถส่งผ่าน int ปกติและคอมไพเลอร์จะไม่ทราบความแตกต่าง หากฟังก์ชันใช้พารามิเตอร์ประเภท tdType แทนคอมไพลเลอร์จะตรวจสอบให้แน่ใจว่ามีการใช้ตัวแปรประเภทที่เหมาะสมระหว่างการเรียกใช้ฟังก์ชัน

นอกจากนี้ยังมีจุดบกพร่องบางคนมีความสามารถในการจับtypedefs ซึ่งอาจจะเป็นประโยชน์มากขึ้นกว่าที่มีประเภทที่กำหนดเองทั้งหมดระบุว่าเป็นชนิดดั้งเดิมพื้นฐานของพวกเขา (มันจะเป็นถ้า#defineถูกนำมาใช้แทน)


2

ไม่ใช่
typedefเป็นคีย์เวิร์ด C ที่สร้างนามแฝงสำหรับประเภท
#define เป็นคำสั่งก่อนตัวประมวลผลที่สร้างเหตุการณ์การแทนที่ข้อความก่อนการคอมไพล์ เมื่อคอมไพเลอร์เข้าสู่โค้ดคำ "#defined" ดั้งเดิมจะไม่มีอีกต่อไป #define ส่วนใหญ่จะใช้สำหรับมาโครและค่าคงที่ทั่วโลก


2
การใช้คำว่า "ตัวชี้" อาจทำให้เกิดความสับสนที่นี่

ตกลง นั่นเป็นเหตุผลที่ฉันย้อนกลับไปและเพิ่มลิงค์ไปยัง typdef บน MSDN - เผื่อว่าใครในอนาคตจะใช้คำถามนี้เพื่อค้นหาว่า typedef คืออะไร แต่บางทีฉันควรเปลี่ยนคำนั้น ...
Travelling Tech Guy

2

AFAIK เลขที่

typedefช่วยคุณตั้งค่า "นามแฝง" ให้กับประเภทข้อมูลที่มีอยู่ สำหรับเช่น typedef char chr;

#defineเป็นคำสั่งพรีโปรเซสเซอร์ที่ใช้ในการกำหนดมาโครหรือการแทนที่รูปแบบทั่วไป สำหรับเช่น #define MAX 100แทนที่เหตุการณ์ทั้งหมดMAXด้วย 100


0

ดังที่ได้กล่าวมาแล้วมีความแตกต่างที่สำคัญระหว่าง#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;

ประกาศว่าทั้งแอปเปิ้ลและกล้วยเหมือนกัน ชื่อที่อยู่ด้านหน้าแตกต่างกัน แต่ทั้งคู่เป็นตัวชี้ไปยังถ่าน


-1

อย่างที่ทุกคนกล่าวไว้ข้างต้นไม่เหมือนกัน ส่วนใหญ่ของคำตอบที่ระบุจะเป็นประโยชน์มากกว่าtypedef #defineแต่ให้ฉันใส่จุดบวกของ#define:
เมื่อรหัสของคุณมีขนาดใหญ่มากกระจายอยู่ทั่วไฟล์จำนวนมากจะดีกว่าที่จะใช้#define; ช่วยในการอ่านง่าย - คุณสามารถประมวลผลโค้ดทั้งหมดล่วงหน้าเพื่อดูนิยามประเภทที่แท้จริงของตัวแปรที่ตำแหน่งของการประกาศนั้นเอง

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