Apakah typedef dan #define sama di c?

Jawaban:

122

Tidak.

#defineadalah token preprocessor: kompilator itu sendiri tidak akan pernah melihatnya.
typedefadalah token compiler: preprocessor tidak mempedulikannya.

Anda dapat menggunakan salah satu untuk mendapatkan efek yang sama, tetapi lebih baik menggunakan yang tepat untuk kebutuhan Anda

#define MY_TYPE int
typedef int My_Type;

Ketika segala sesuatunya menjadi "berbulu", menggunakan alat yang tepat membuatnya menjadi benar

#define FX_TYPE void (*)(int)
typedef void (*stdfx)(int);

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
sumber
3
Setelah typedef stdfx, objek yang valid dari tipe tersebut adalah pointer ke fungsi yang menerima int dan tidak mengembalikan nilai.
pmg
1
Mengapa #define gagal di casec dari function pointer sebagai argumen?
Allahjane
2
@Allahjane: perluasan menjadi void fx_def(void (*)(int) fx);; deklarasi yang benar adalah void fx_def(void (*fx)(int));.
pmg
5
Fungsi pointer bisa dilakukan dengan macro, hanya jika Anda siap untuk menyerah sintaks: #define FX_TYPE(f) void (*f)(int). Anda kemudian akan mendeklarasikan fungsi Anda sebagai:void fx_def(FX_TYPE(fx));
plafer
229

typedefmematuhi aturan pelingkupan seperti variabel, sedangkan definetetap valid hingga akhir unit kompilasi (atau hingga cocok undef).

Juga, beberapa hal dapat dilakukan dengan typedefyang tidak dapat dilakukan define.
Sebagai contoh:

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
Andreas Grech
sumber
23

Tidak, mereka tidak sama. Sebagai contoh:

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

Setelah praproses, garis itu meluas ke

int* a, b;

Semoga Anda melihat masalahnya; hanya aakan memiliki tipe int *; bakan dideklarasikan sebagai polos int(karena *terkait dengan deklarator, bukan penentu tipe).

Bandingkan itu dengan

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

Dalam hal ini, keduanya adan bakan memiliki tipe int *.

Ada seluruh kelas typedef yang tidak bisa ditiru dengan makro preprocessor, seperti pointer ke fungsi atau array:

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

Coba lakukan itu dengan makro praprosesor.

John Bode
sumber
13

#define mendefinisikan makro.
typedef mendefinisikan tipe.

Sekarang mengatakan itu, berikut adalah beberapa perbedaan:

Dengan #define, Anda dapat menentukan konstanta yang dapat digunakan dalam waktu kompilasi. Konstanta dapat digunakan dengan #ifdef untuk memeriksa bagaimana kode dikompilasi, dan mengkhususkan kode tertentu sesuai dengan parameter kompilasi.
Anda juga dapat menggunakan #define untuk mendeklarasikan fungsi Makro temukan-dan-ganti miniatur .

typedef dapat digunakan untuk memberikan alias pada tipe (yang mungkin bisa Anda lakukan dengan #define juga), tetapi lebih aman karena sifat konstanta #define yang temukan dan ganti .
Selain itu, Anda dapat menggunakan deklarasi maju dengan typedef yang memungkinkan Anda mendeklarasikan tipe yang akan digunakan, tetapi belum ditautkan ke file yang Anda tulis.

Yochai Timmer
sumber
apa yang Anda maksud dengan menemukan dan mengganti sifat #define? , Terima kasih
Mohamed El Shenawy
1
Artinya sebelum kompilasi, preprocessor akan menemukan semua makro dan menggantinya dengan sintaks aslinya
Pangeran Vijay Pratap
"typedef bisa digunakan untuk memberi alias untuk jenis" ini menjelaskan tujuan saya, terima kasih.
Dave Voyles
8

Makro preprocessor (" #define's") adalah alat pengganti leksikal a la "search and replace". Mereka sepenuhnya agnostik dari bahasa pemrograman dan tidak memahami apa yang Anda coba lakukan. Anda dapat menganggap mereka sebagai mekanik salin / tempel yang dimuliakan - terkadang itu berguna, tetapi Anda harus menggunakannya dengan hati-hati.

Typedefs adalah fitur bahasa C yang memungkinkan Anda membuat alias untuk tipe. Ini sangat berguna untuk membuat tipe gabungan yang rumit (seperti struct dan pointer fungsi) dapat dibaca dan diatur (dalam C ++ bahkan ada situasi di mana Anda harus mengetikkan sebuah tipe).

Untuk (3): Anda harus selalu lebih memilih fitur bahasa daripada makro praprosesor jika memungkinkan! Jadi selalu gunakan typedef untuk tipe, dan nilai konstan untuk konstanta. Dengan begitu, kompilator benar-benar dapat berinteraksi dengan Anda secara berarti. Ingatlah bahwa kompilator adalah teman Anda, jadi Anda harus memberitahukannya sebanyak mungkin. Makro preprocessor melakukan kebalikannya dengan menyembunyikan semantik Anda dari compiler.

Kerrek SB
sumber
Dapatkah Anda memberi tahu satu contoh di C ++ di mana Anda harus mengetikkan sebuah tipe? Saya hanya ingin tahu tentang itu.
jyz
@jyzuz: Ada sesuatu jika Anda ingin fungsi anggota mengembalikan array penunjuk fungsi, atau semacamnya - jika Anda mencoba mengeja jenisnya, GCC sebenarnya mengatakan "Anda harus menggunakan typedef".
Kerrek SB
4

Mereka sangat berbeda, meskipun mereka sering digunakan untuk mengimplementasikan tipe data khusus (yang saya asumsikan adalah pertanyaan ini).

Seperti yang disebutkan pmg, #defineditangani oleh pra-prosesor (seperti operasi potong-dan-tempel) sebelum kompilator melihat kode, dan typedefdiinterpretasikan oleh kompilator.

Salah satu perbedaan utama (setidaknya dalam hal mendefinisikan tipe data) adalah typedefmemungkinkan pemeriksaan tipe yang lebih spesifik. Sebagai contoh,

#define defType int
typedef int tdType

defType x;
tdType y;

Di sini, compiler melihat variabel x sebagai int, tetapi variabel y sebagai tipe data yang disebut 'tdType' yang ukurannya sama dengan int. Jika Anda menulis fungsi yang mengambil parameter tipe defType, pemanggil bisa meneruskan int normal dan kompilator tidak akan tahu bedanya. Jika fungsi tersebut mengambil parameter tipe tdType, compiler akan memastikan bahwa variabel dengan tipe yang tepat digunakan selama panggilan fungsi.

Selain itu, beberapa debugger memiliki kemampuan untuk menangani typedefs, yang bisa jauh lebih berguna daripada mencantumkan semua tipe kustom sebagai tipe primitif yang mendasarinya (seperti yang akan terjadi jika #definedigunakan sebagai gantinya).

bta
sumber
2

Tidak.
Typedef adalah kata kunci C yang membuat alias untuk suatu tipe.
#define adalah instruksi pra-prosesor, yang membuat peristiwa penggantian teks sebelum kompilasi. Ketika kompilator mendapatkan kode tersebut, kata "#defined" asli tidak ada lagi. #define sebagian besar digunakan untuk makro dan konstanta global.

Bepergian Tech Guy
sumber
2
Penggunaan istilah "pointer" dapat menyebabkan kebingungan di sini.
Sepakat. Itu sebabnya saya kembali dan menambahkan tautan ke typdef di MSDN - kalau-kalau ada orang di masa mendatang akan menggunakan pertanyaan ini untuk menemukan apa itu typedef. Tapi mungkin saya harus mengubah kata itu ...
Travelling Tech Guy
2

AFAIK, Tidak.

typedefmembantu Anda menyiapkan "alias" untuk tipe data yang ada. Misalnya. typedef char chr;

#defineadalah arahan preprocessor yang digunakan untuk mendefinisikan makro atau substitusi pola umum. Misalnya. #define MAX 100, gantikan semua kemunculan MAXdengan 100

Chris Tang
sumber
0

Seperti disebutkan di atas, ada perbedaan utama antara #definedan typedef. Cara yang tepat untuk memikirkannya adalah dengan melihat typedef sebagai tipe "dikemas" yang lengkap. Artinya Anda tidak dapat menambahkannya setelah Anda mendeklarasikannya.

Anda bisa memperluas nama jenis makro dengan penentu jenis lain, tapi bukan nama jenis yang diketik:

#define fruit int
unsigned fruit i;   // works fine

typedef int fruit;
unsigned fruit i;   // illegal

Selain itu, nama typedef menyediakan tipe untuk setiap deklarasi dalam deklarasi.

#define fruit int *
fruit apple, banana;

Setelah ekspansi makro, baris kedua menjadi:

int *apple, banana;

Apel adalah penunjuk ke int, sedangkan banana adalah int. Dibandingkan. seorang typedef seperti ini:

typedef char *fruit;
fruit apple, banana;

menyatakan apel dan pisang sama. Nama di depan berbeda, tetapi keduanya mengarah ke karakter.

paul
sumber
-1

Seperti yang dikatakan semua orang di atas, mereka tidak sama. Sebagian besar jawaban menunjukkan typedeflebih menguntungkan daripada #define. Tapi izinkan saya memberi nilai tambah #define:
ketika kode Anda sangat besar, tersebar di banyak file, lebih baik digunakan #define; itu membantu dalam keterbacaan - Anda cukup memproses semua kode untuk melihat definisi tipe sebenarnya dari variabel di tempat deklarasinya sendiri.

abcoep
sumber