Ini memiliki kekurangan saya pikir Anda tidak dapat membuat daftar tautan dengan struct anonim karena garis struct * ptrdi dalam struct akan menyebabkan kesalahan
Raghib Ahsan
9
'Jawaban yang lebih menyeluruh dan tepat' adalah Perbedaan antara struct dan typedef struct dalam C ++ , dan ada perbedaan signifikan antara C dan C ++ di area ini yang membuat jawaban itu tidak sepenuhnya sesuai untuk pertanyaan tentang C.
Seperti kata Greg Hewgill, typedef berarti Anda tidak perlu lagi menulis di structsemua tempat. Itu tidak hanya menyimpan penekanan tombol, itu juga dapat membuat kode lebih bersih karena memberikan sedikit lebih banyak abstraksi.
menjadi lebih bersih ketika Anda tidak perlu melihat kata kunci "struct" di semua tempat, itu terlihat lebih seolah-olah ada jenis yang disebut "Point" dalam bahasa Anda. Yang, setelah itu typedef, adalah kasus saya kira.
Perhatikan juga bahwa ketika contoh Anda (dan milik saya) mengabaikan penamaan struct itu sendiri, sebenarnya penamaan itu juga berguna ketika Anda ingin memberikan jenis buram. Maka Anda akan memiliki kode seperti ini di header, misalnya:
Dalam kasus yang terakhir ini, Anda tidak dapat mengembalikan Poin dengan nilai, karena definisinya disembunyikan dari pengguna file header. Ini adalah teknik yang digunakan secara luas di GTK + , misalnya.
UPDATE Perhatikan bahwa ada juga proyek-proyek C yang sangat terkenal di mana penggunaan typedefuntuk menyembunyikan structini dianggap sebagai ide yang buruk, kernel Linux mungkin adalah proyek yang paling terkenal. Lihat Bab 5 dokumen The Linux Kernel CodingStyle untuk kata-kata marah Linus. :) Maksud saya adalah bahwa "harus" dalam pertanyaan itu mungkin tidak diatur, setelah semua.
Anda tidak boleh menggunakan pengidentifikasi dengan garis bawah yang diikuti oleh huruf besar, mereka dicadangkan (lihat bagian 7.1.3 paragraf 1). Meskipun tidak terlalu menjadi masalah, ini adalah perilaku yang secara teknis tidak terdefinisi saat Anda menggunakannya (7.1.3 paragraf 2).
dreamlax
16
@dreamlax: Jika tidak jelas bagi orang lain, itu hanya memulai pengidentifikasi dengan garis bawah dan huruf besar yang tidak boleh Anda lakukan; Anda bebas menggunakannya di tengah pengenal.
brianmearns
12
Sangat menarik bahwa contoh yang diberikan di sini (di mana typedef mencegah penggunaan "struct" "all over the place") sebenarnya lebih panjang dari kode yang sama tanpa typedef, karena itu menghemat tepat satu penggunaan kata "struct". Smidgen abstraksi yang diperoleh jarang dibandingkan menguntungkan dengan kebingungan tambahan.
William Pursell
7
@Rerito fyi, halaman 166 dari draft C99 , Semua pengidentifikasi yang dimulai dengan garis bawah dan huruf besar atau garis bawah lainnya selalu dicadangkan untuk penggunaan apa pun. Dan Semua pengidentifikasi yang dimulai dengan garis bawah selalu dicadangkan untuk digunakan sebagai pengidentifikasi dengan cakupan file dalam ruang biasa dan nama tag.
e2-e4
10
Cukup menarik, pedoman pengkodean kernel linux mengatakan kita harus lebih konservatif dalam menggunakan typedefs (bagian 5): kernel.org/doc/Documentation/CodingStyle
gsingh2011
206
Sungguh menakjubkan berapa banyak orang yang melakukan kesalahan ini. TOLONG jangan mengetik struct di C, itu tidak perlu mencemari namespace global yang biasanya sudah sangat tercemar di program C besar.
Juga, struct yang diketik tanpa nama tag adalah penyebab utama pemaksaan hubungan pemesanan yang tidak perlu di antara file header.
Mempertimbangkan:
#ifndef FOO_H
#define FOO_H 1#define FOO_DEF (0xDEADBABE)struct bar;/* forward declaration, defined in bar.h*/struct foo {struct bar *bar;};#endif
Dengan definisi seperti itu, tidak menggunakan typedef, adalah mungkin bagi unit compiland untuk memasukkan foo.h untuk mendapatkan FOO_DEFdefinisi tersebut. Jika tidak mencoba untuk melakukan dereferensi anggota 'bar' dari foostruct maka tidak perlu menyertakan file "bar.h".
Juga, karena ruang nama berbeda antara nama tag dan nama anggota, dimungkinkan untuk menulis kode yang sangat mudah dibaca seperti:
Apa yang lebih menakjubkan adalah bahwa 13 bulan setelah jawaban ini diberikan, saya adalah orang pertama yang mengangkatnya! typedef'ing structs adalah salah satu penyalahgunaan terbesar dari C, dan tidak memiliki tempat dalam kode yang ditulis dengan baik. typedef berguna untuk men-de-obfuscating tipe pointer fungsi yang berbelit-belit dan benar-benar tidak berguna.
William Pursell
28
Peter van der Linden juga membuat kasus terhadap typedefing structs dalam bukunya yang mencerahkan "Expert C Programming - Deep C Secrets". Intinya adalah: Anda INGIN tahu bahwa sesuatu adalah struct atau persatuan, bukan HIDE itu.
Jens
34
Gaya pengkodean kernel Linux secara eksplisit melarang struct typedefing. Bab 5: Typedefs: "Adalah kesalahan untuk menggunakan typedef untuk struktur dan pointer." kernel.org/doc/Documentation/CodingStyle
jasso
63
Apa manfaatnya, tepatnya, mengetik "struct" berulang-ulang memberikan? Dan berbicara tentang polusi, mengapa Anda ingin memiliki struct dan fungsi / variabel / typedef dengan nama yang sama di namespace global (kecuali itu typedef untuk fungsi yang sama)? Pola aman untuk digunakan typedef struct X { ... } X. Dengan begitu Anda bisa menggunakan formulir singkat Xuntuk membahas struct di mana pun definisi tersedia, tetapi masih dapat meneruskan dan mendeklarasikan struct Xketika diinginkan.
Pavel Minaev
7
Saya pribadi sangat jarang jika pernah menggunakan typedef, saya tidak akan mengatakan orang lain tidak boleh menggunakannya, itu hanya bukan gaya saya. Saya suka melihat struct sebelum tipe variabel jadi saya langsung tahu itu sebuah struct. Argumen yang lebih mudah diketik agak timpang, memiliki variabel yang merupakan huruf tunggal juga lebih mudah untuk diketik, juga dengan pelengkapan otomatis betapa sulitnya mengetik struct saat ini di mana saja.
Aturan bahasa C untuk penamaan struct agak eksentrik, tetapi cukup berbahaya. Namun, ketika diperluas ke kelas-kelas di C ++, aturan-aturan yang sama membuka sedikit celah bagi bug untuk menjelajah.
Di C, namanya muncul di
struct s
{...};
adalah sebuah tag. Nama tag bukan nama jenis. Mengingat definisi di atas, deklarasi seperti
s x;/* error in C */
s *p;/* error in C */
ada kesalahan dalam C. Anda harus menuliskannya sebagai
struct s x;/* OK */struct s *p;/* OK */
Nama-nama serikat pekerja dan enumerasi juga merupakan tag dan bukan tipe.
Di C, tag berbeda dari semua nama lain (untuk fungsi, tipe, variabel, dan konstanta enumerasi). Kompiler C memelihara tag dalam tabel simbol yang secara konseptual jika tidak secara fisik terpisah dari tabel yang menampung semua nama lain. Dengan demikian, dimungkinkan bagi program C untuk memiliki tag dan nama lain dengan ejaan yang sama dalam cakupan yang sama. Sebagai contoh,
struct s s;
adalah deklarasi yang valid yang menyatakan variabel s dari tipe struct s. Ini mungkin bukan praktik yang baik, tetapi kompiler C harus menerimanya. Saya belum pernah melihat alasan mengapa C dirancang dengan cara ini. Saya selalu berpikir itu adalah kesalahan, tapi itu dia.
Banyak programmer (termasuk Anda yang benar-benar) lebih suka menganggap nama struct sebagai nama tipe, sehingga mereka mendefinisikan alias untuk tag menggunakan typedef. Misalnya, mendefinisikan
struct s
{...};typedefstruct s S;
memungkinkan Anda menggunakan S sebagai ganti struct, seperti pada
S x;
S *p;
Suatu program tidak dapat menggunakan S sebagai nama tipe dan variabel (atau konstanta fungsi atau enumerasi):
S S;// error
Ini bagus.
Nama tag dalam definisi struct, gabungan, atau enum adalah opsional. Banyak programmer melipat definisi struct ke dalam typedef dan membuang tag sama sekali, seperti pada:
typedefstruct{...} S;
Artikel yang ditautkan juga memiliki diskusi tentang bagaimana perilaku C ++ yang tidak memerlukan typedefdapat menyebabkan masalah persembunyian nama halus. Untuk mencegah masalah ini, itu ide yang bagus untuk typedefkelas dan struct Anda di C ++, juga, meskipun pada pandangan pertama tampaknya tidak perlu. Di C ++, dengan typedefnama bersembunyi menjadi kesalahan yang kompiler memberitahu Anda tentang daripada sumber tersembunyi dari potensi masalah.
Salah satu contoh di mana nama tag sama dengan nama non-tag dalam program (POSIX atau Unix) dengan int stat(const char *restrict path, struct stat *restrict buf)fungsi. Di sana Anda memiliki fungsi statdi ruang nama biasa dan struct statdi ruang nama tag.
Jonathan Leffler
2
pernyataan Anda, SS; // error .... IS SALAH Ini bekerja dengan baik. Maksud saya pernyataan Anda bahwa "kita tidak dapat memiliki nama yang sama untuk tag typedef dan var" SALAH ...
tolong
63
Menggunakan typedefmenghindari harus menulis structsetiap kali Anda mendeklarasikan variabel jenis itu:
struct elem
{int i;char k;};
elem user;// compile error!struct elem user;// this is correct
ok kita tidak mengalami masalah di C ++. Jadi mengapa tidak ada yang menghapus kesalahan itu dari kompiler C dan membuatnya sama seperti di C ++. Ok C ++ memiliki beberapa area aplikasi yang berbeda dan juga memiliki fitur-fitur canggih. asli C?
Manoj Doubts
4
Manoj, nama tag ("struct foo") diperlukan ketika Anda perlu mendefinisikan struct yang mereferensikan dirinya. misalnya penunjuk "berikutnya" dalam daftar yang ditautkan. Lebih penting lagi, kompiler mengimplementasikan standar, dan itulah yang dikatakan standar untuk dilakukan.
Michael Carman
41
Ini bukan kesalahan dalam kompiler C, itu bagian dari desain. Mereka mengubah itu untuk C ++, yang saya pikir membuat segalanya lebih mudah, tetapi itu tidak berarti perilaku C salah.
Herms
5
sayangnya banyak 'programmer' mendefinisikan struct kemudian mengetiknya dengan beberapa nama 'tidak terkait' (seperti struct myStruct ...; typedef struct myStruct susan *; Dalam hampir semua kasus typedef mengarah ke apa-apa selain mengacaukan kode, menyembunyikan definisi aktual dari variabel / parameter, dan salah mengarahkan semua orang, termasuk penulis asli kode.
user3629249
1
@ user3629249 Saya setuju dengan Anda bahwa gaya pemrograman yang disebutkan itu mengerikan, tetapi ini bukan alasan untuk merendahkan typedefstruktur secara umum. Anda juga bisa melakukannya typedef struct foo foo;. Tentu saja structkata kunci tidak diperlukan lebih dari itu yang dapat menjadi petunjuk yang berguna bahwa jenis alias yang kita lihat adalah alias untuk struktur tetapi itu tidak buruk secara umum. Pertimbangkan juga kasus di mana pengenal jenis alias yang dihasilkan dari typedefmenunjukkan bahwa itu adalah alias untuk struktur, fe: typedef struct foo foo_struct;.
RobertS mendukung Monica Cellio
38
Satu alasan bagus lainnya untuk selalu mengetik enum dan struct hasil dari masalah ini:
Perhatikan kesalahan ketik di EnumDef di struct (Enu u mDef)? Ini mengkompilasi tanpa kesalahan (atau peringatan) dan (tergantung pada interpretasi literal dari Standar C) yang benar. Masalahnya adalah bahwa saya baru saja membuat definisi enumerasi (kosong) baru dalam struct saya. Saya tidak (sebagaimana dimaksud) menggunakan definisi EnumDef sebelumnya.
Dengan typdef, kesalahan ketik yang serupa akan menghasilkan kesalahan kompiler untuk menggunakan jenis yang tidak dikenal:
Lebih buruk lagi, kesalahan ketik Anda mungkin bertepatan dengan tag yang berbeda. Dalam kasus struct, ini dapat mengakibatkan seluruh program mengkompilasi dengan benar dan memiliki perilaku runtime yang tidak terdefinisi.
MM
3
definisi ini: 'typedef {FIRST_ITEM, SECOND_ITEM} EnumDef;' tidak mendefinisikan enum. Saya telah menulis ratusan program besar dan memiliki nasib buruk untuk melakukan pemeliharaan pada program yang ditulis orang lain. Dari pengalaman sulit, menggunakan typedef pada struct hanya menyebabkan masalah. Mudah-mudahan programmer tidak cacat sehingga mereka memiliki masalah mengetik definisi penuh ketika mereka mendeklarasikan instance struct. C bukan Basic, jadi mengetikkan beberapa karakter lagi tidak merugikan pengoperasian program.
user3629249
2
Bagi mereka yang merasa tidak suka mengetik lebih dari jumlah minimum karakter absolut, mungkin saya sarankan bergabung dengan beberapa kelompok yang mencoba menulis aplikasi dengan jumlah penekanan tombol minimum. Hanya saja, jangan gunakan 'keahlian' baru mereka di lingkungan kerja, terutama lingkungan kerja yang dengan ketat melakukan tinjauan sejawat
user3629249
Catatan, biasanya tidak disarankan untuk menggunakan enumtipe, karena banyak kompiler memancarkan peringatan aneh ketika menggunakannya 'salah'. Misalnya, menginisialisasi suatu enumke 0 mungkin memberikan peringatan 'integer constant not in enum'. Pernyataan ke depan enumjuga tidak diizinkan. Orang harus menggunakan int(atau unsigned int) sebagai gantinya.
yyny
5
Contoh itu tidak dikompilasi, saya juga tidak mengharapkannya. Mengkompilasi Debug / test.o test.c: 10: 17: error: bidang memiliki tipe 'enum EnuumDef' yang tidak lengkap 'enum EnuumDef MyEnum; ^ test.c: 10: 8: catatan: deklarasi maju 'enum EnuumDef' enum EnuumDef MyEnum; ^ 1 kesalahan dihasilkan. gnuc, dengan std = c99.
Merupakan kesalahan untuk menggunakan typedef untuk struktur dan pointer. Ketika Anda melihat a
vps_t a;
di sumbernya, apa artinya?
Sebaliknya, jika dikatakan
struct virtual_container *a;
Anda benar-benar dapat mengetahui apa itu "a".
Banyak orang berpikir bahwa mengetik "membantu keterbacaan". Tidak begitu. Mereka hanya berguna untuk:
(A) objek benar-benar buram (di mana typedef secara aktif digunakan untuk menyembunyikan apa objek itu).
Contoh: "pte_t" dll. Objek buram yang hanya dapat Anda akses menggunakan fungsi accessor yang tepat.
CATATAN! Ketidakjelasan dan "fungsi pengakses" tidak baik dalam diri mereka. Alasan kami memilikinya untuk hal-hal seperti pte_t dll. Adalah benar-benar nol informasi yang dapat diakses di sana.
(B) Hapus jenis integer, di mana abstraksi membantu menghindari kebingungan apakah itu "int" atau "panjang".
u8 / u16 / u32 adalah typedef yang sangat bagus, meskipun mereka masuk dalam kategori (d) lebih baik daripada di sini.
CATATAN! Sekali lagi - perlu ada alasan untuk ini. Jika ada sesuatu yang "tidak ditandai lama", maka tidak ada alasan untuk melakukannya
typedefunsignedlongmyflags_t;
tetapi jika ada alasan yang jelas mengapa itu dalam keadaan tertentu mungkin merupakan "unsigned int" dan di bawah konfigurasi lain mungkin "unsigned long", maka tentu saja silakan dan gunakan typedef.
(C) ketika Anda menggunakan jarang untuk benar-benar membuat tipe baru untuk pemeriksaan tipe.
(d) Tipe baru yang identik dengan tipe C99 standar, dalam keadaan tertentu tertentu.
Meskipun hanya membutuhkan waktu singkat bagi mata dan otak untuk menjadi terbiasa dengan tipe standar seperti 'uint32_t', toh sebagian orang tetap menolak penggunaannya.
Oleh karena itu, tipe 'u8 / u16 / u32 / u64' khusus Linux dan setara yang ditandatangani yang identik dengan tipe standar diizinkan - meskipun mereka tidak wajib dalam kode baru Anda sendiri.
Saat mengedit kode yang ada yang sudah menggunakan satu atau beberapa tipe lainnya, Anda harus menyesuaikan dengan pilihan yang ada dalam kode itu.
(e) Jenis aman untuk digunakan di ruang pengguna.
Dalam struktur tertentu yang terlihat oleh userspace, kami tidak dapat membutuhkan tipe C99 dan tidak dapat menggunakan formulir 'u32' di atas. Dengan demikian, kami menggunakan __u32 dan tipe serupa di semua struktur yang dibagi dengan userspace.
Mungkin ada kasus-kasus lain juga, tetapi aturan dasarnya harus TIDAK PERNAH menggunakan typedef kecuali Anda dapat dengan jelas mencocokkan salah satu aturan itu.
Secara umum, sebuah pointer, atau struct yang memiliki elemen yang dapat diakses secara langsung tidak boleh berupa typedef.
'Ketidakjelasan dan "fungsi pengakses" tidak baik dalam diri mereka sendiri. Adakah yang bisa menjelaskan mengapa? Saya akan berpikir menyembunyikan informasi dan enkapsulasi akan menjadi ide yang sangat bagus.
Yawar
5
@ Yawar Saya baru saja membaca dokumen ini dan memiliki pemikiran yang persis sama. Tentu, C tidak berorientasi objek, tetapi abstraksi masih merupakan sesuatu.
Baldrickk
12
Ternyata ada pro dan kontra. Sumber informasi yang bermanfaat adalah buku mani "Pemrograman C Pakar" ( Bab 3 ). Secara singkat, di C Anda memiliki beberapa ruang nama: tag, tipe, nama anggota, dan pengidentifikasi . typedefmemperkenalkan alias untuk suatu jenis dan menempatkannya di tag namespace. Yaitu,
typedefstructTag{...members...}Type;
mendefinisikan dua hal. Satu Tag di namespace tag dan satu Ketik dalam tipe namespace. Jadi Anda bisa melakukan keduanya Type myTypedan struct Tag myTagType. Deklarasi suka struct Type myTypeatau Tag myTagTypeilegal. Selain itu, dalam deklarasi seperti ini:
typedefType*Type_ptr;
kita mendefinisikan pointer ke Tipe kita. Jadi jika kita menyatakan:
kemudian var1, var2dan myTagType1pointer ke Ketik tetapi myTagType2tidak.
Dalam buku yang disebutkan di atas, disebutkan bahwa struct typedefing tidak terlalu berguna karena hanya menyelamatkan programmer dari menulis kata struct. Namun, saya keberatan, seperti banyak programmer C lainnya. Meskipun kadang-kadang ternyata mengaburkan beberapa nama (itu sebabnya tidak disarankan dalam basis kode besar seperti kernel) ketika Anda ingin menerapkan polimorfisme dalam C, banyak membantu mencari di sini untuk rincian . Contoh:
Jadi, Anda dapat mengakses anggota luar ( flags) dengan struct bagian dalam ( MyPipe) melalui casting. Bagi saya itu kurang membingungkan untuk melemparkan seluruh jenis daripada melakukan (struct MyWriter_ *) s;setiap kali Anda ingin melakukan fungsi seperti itu. Dalam kasus ini referensi singkat adalah masalah besar terutama jika Anda menggunakan teknik dalam kode Anda.
Akhirnya, aspek terakhir dengan typedeftipe ed adalah ketidakmampuan untuk memperpanjangnya, berbeda dengan makro. Jika misalnya, Anda memiliki:
#define X char[10] or
typedefchar Y[10]
Anda kemudian dapat mendeklarasikan
unsigned X x; but not
unsigned Y y;
Kami tidak terlalu peduli untuk ini karena struct karena tidak berlaku untuk specifier penyimpanan ( volatiledan const).
"typedef memperkenalkan alias untuk suatu tipe dan menempatkannya di tag namespace. Yaitu" typedef struct Tag{ ...members... }Type; "mendefinisikan dua hal" tidak cukup masuk akal. jika typedef mendefinisikan tag maka 'Ketik' di sini juga harus menjadi tag. Yang benar adalah definisi mendefinisikan 2 tag dan 1 jenis (atau 2 jenis dan 1 tag tidak yakin.): struct Tag, TagDan Type. struct Tagjelas merupakan suatu tipe. Tagadalah sebuah tag. tetapi kebingungannya adalah apakah Typesebuah tag atau tipe
Qwertyzw
12
Saya tidak berpikir deklarasi maju bahkan mungkin dengan typedef. Penggunaan struct, enum, dan union memungkinkan untuk meneruskan deklarasi ketika dependensi (tahu tentang) adalah dua arah.
Style: Penggunaan typedef di C ++ cukup masuk akal. Hampir bisa diperlukan ketika berhadapan dengan templat yang memerlukan banyak dan / atau parameter variabel. Typedef membantu menjaga penamaan tetap lurus.
Tidak demikian halnya dalam bahasa pemrograman C. Penggunaan typedef paling sering tidak memiliki tujuan selain mengaburkan penggunaan struktur data. Karena hanya {struct (6), enum (4), union (5)} jumlah penekanan tombol yang digunakan untuk mendeklarasikan tipe data, hampir tidak ada gunanya untuk alias alias struct. Apakah tipe data itu gabungan atau struktur? Menggunakan deklarasi non-typdefed langsung membuat Anda langsung tahu apa itu.
Perhatikan bagaimana Linux ditulis dengan menghindari ketat dari typedef omong kosong alias ini membawa. Hasilnya adalah gaya minimalis dan bersih.
Bersih tidak akan berulang di structmana - mana ... Typedef membuat tipe baru. Apa yang kamu gunakan? Jenis. Kami tidak peduli apakah itu struct, union, atau enum, itu sebabnya kami mengetiknya.
GManNickG
13
Tidak, kami tidak peduli apakah itu struct atau union, versus enum atau beberapa jenis atom. Anda tidak bisa memaksa struct ke integer atau ke pointer (atau ke jenis lain, dalam hal ini), yang hanya Anda terkadang harus menyimpan beberapa konteks. Memiliki kata kunci 'struct' atau 'union' di sekitar meningkatkan lokalitas penalaran. Tidak ada yang mengatakan Anda perlu tahu apa yang ada di dalam struct.
Bernd Jendrissek
1
@BerndJendrissek: Structs dan unions berbeda dari tipe lain, tetapi haruskah kode klien peduli tentang mana dari dua hal (struct atau union) yang kira-kira seperti FILEitu?
supercat
4
@supercat FILE adalah penggunaan typedef yang baik. Saya pikir typedef terlalu sering digunakan , bukan karena kesalahan bahasa. IMHO menggunakan typedef untuk semuanya adalah bau kode "terlalu banyak generalisasi". Perhatikan bahwa Anda mendeklarasikan variabel sebagai FILE * foo, tidak pernah sebagai FILE foo. Bagi saya, ini penting.
Bernd Jendrissek
2
@supercat: "Jika variabel pengidentifikasi file bertipe FILE daripada FILE * ..." Tapi itulah ambiguitas yang diaktifkan oleh typedef! Kami hanya terbiasa membuka FILE * jadi kami tidak khawatir tentang hal itu, tetapi setiap kali Anda menambahkan typedef Anda memperkenalkan sedikit overhead kognitif: apakah API ini ingin foo_t args atau foo_t *? Membawa 'struct' secara eksplisit meningkatkan lokalitas penalaran, jika dengan biaya beberapa karakter per definisi fungsi.
Bernd Jendrissek
4
Mari kita mulai dengan dasar-dasar dan terus maju.
Berikut adalah contoh definisi Struktur:
struct point
{int x, y;};
Di sini namanya pointopsional.
Struktur dapat dideklarasikan selama definisi atau setelahnya.
Mendeklarasikan selama definisi
struct point
{int x, y;} first_point, second_point;
Mendeklarasikan setelah definisi
struct point
{int x, y;};struct point first_point, second_point;
Sekarang, perhatikan baik-baik kasus terakhir di atas; Anda perlu menulis struct pointuntuk mendeklarasikan Struktur jenis itu jika Anda memutuskan untuk membuat jenis itu di kemudian hari dalam kode Anda.
Masukkan typedef. Jika Anda bermaksud membuat Struktur baru (Struktur adalah tipe data khusus) di lain waktu di program Anda menggunakan cetak biru yang sama, menggunakan typedefselama definisi mungkin merupakan ide yang bagus karena Anda dapat menyimpan beberapa pengetikan bergerak maju.
typedefstruct point
{int x, y;}Points;Points first_point, second_point;
Sebuah kata hati-hati saat memberi nama jenis kustom Anda
Tidak ada yang mencegah Anda menggunakan akhiran _t di akhir nama jenis kustom Anda tetapi standar POSIX cadangan penggunaan akhiran _t untuk menunjukkan nama jenis perpustakaan standar.
nama yang Anda (opsional) berikan kepada struct disebut nama tag dan, seperti yang telah dicatat, bukan tipe itu sendiri. Untuk sampai ke tipe memerlukan awalan struct.
Selain GTK +, saya tidak yakin tagname digunakan seperti biasanya seperti typedef untuk tipe struct, jadi di C ++ yang dikenali dan Anda dapat menghilangkan kata kunci struct dan menggunakan tagname sebagai nama tipe juga:
structMyStruct{int i;};// The following is legal in C++:MyStruct obj;
obj.i =7;
A> typdef membantu dalam arti dan dokumentasi suatu program dengan memungkinkan pembuatan sinonim yang lebih bermakna untuk tipe data . Selain itu, mereka membantu membuat parameter program terhadap masalah portabilitas (K&R, pg147, C prog lang).
B>
suatu struktur mendefinisikan suatu tipe . Structs memungkinkan pengelompokan yang mudah dari kumpulan vars untuk kenyamanan penanganan (K&R, pg127, C prog lang.) Sebagai satu unit
C> mengetikkan struct dijelaskan dalam A di atas.
D> Bagi saya, struct adalah tipe kustom atau wadah atau koleksi atau ruang nama atau tipe kompleks, sedangkan typdef hanyalah sarana untuk membuat lebih banyak nama panggilan.
Diperlukan mengetikkan C99. Itu sudah usang, tetapi banyak alat (ala HackRank) menggunakan c99 sebagai implementasi C murni. Dan typedef diperlukan di sana.
Saya tidak mengatakan mereka harus berubah (mungkin memiliki dua opsi C) jika persyaratannya berubah, kita yang sedang belajar untuk wawancara di situs adalah SOL.
Pertanyaannya adalah tentang C, bukan C++. Di Ctypedef 'diperlukan' (dan kemungkinan besar akan selalu demikian). 'Diperlukan' seperti pada, Anda tidak akan dapat mendeklarasikan variabel Point varName;dan memiliki tipe yang sama dengan struct Point;tanpa typedef struct Point Point;.
yyny
0
Dalam bahasa pemrograman 'C' kata kunci 'typedef' digunakan untuk mendeklarasikan nama baru untuk beberapa objek (struct, array, function..enum type). Sebagai contoh, saya akan menggunakan 'struct-s'. Dalam 'C' kita sering menyatakan 'struct' di luar fungsi 'utama'. Sebagai contoh:
struct complex{int real_part, img_part }COMPLEX;
main(){struct KOMPLEKS number;// number type is now a struct type
number.real_part =3;
number.img_part =-1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);}
Setiap kali saya memutuskan untuk menggunakan tipe struct saya akan membutuhkan kata kunci ini 'struct' something '' name '.' Typedef 'hanya akan mengubah nama tipe itu dan saya dapat menggunakan nama baru itu di program saya setiap kali saya mau. Jadi kode kita adalah:
typedefstruct complex{int real_part, img_part;}COMPLEX;//now COMPLEX is the new name for this structure and if I want to use it without// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number;// number is now the same type as in the first example
number.real_part =1;
number.img)part =5;
printf("%d %d \n", number.real_part, number.img_part);}
Jika Anda memiliki beberapa objek lokal (struct, array, bernilai) yang akan digunakan di seluruh program Anda, Anda bisa memberinya nama menggunakan 'typedef'.
Sama sekali, dalam bahasa C, struct / union / enum adalah instruksi makro yang diproses oleh preprocessor bahasa C (jangan salah dengan preprocessor yang memperlakukan "#include" dan lainnya)
jadi:
struct a
{int i;};struct b
{struct a;int i;int j;};
struct b dikeluarkan sebagai sesuatu seperti ini:
struct b
{struct a
{int i;};int i;int j;}
jadi, pada waktu kompilasi, ia berevolusi di stack sebagai sesuatu seperti: b: int ai int i int j
itu juga mengapa sulit untuk memiliki struct selfreferent, putaran preprocessor C dalam loop deklarasi yang tidak dapat diakhiri.
typedef adalah specifier tipe, yang berarti hanya proses compiler C dan itu bisa dilakukan seperti yang dia inginkan untuk mengoptimalkan implementasi kode assembler. Itu juga tidak mengeluarkan anggota tipe par bodoh seperti préprocessor lakukan dengan struct tetapi menggunakan algoritma konstruksi referensi yang lebih kompleks, jadi konstruksi seperti:
typedefstruct a A;//anticipated declaration for member declarationtypedefstruct a //Implemented declaration{
A* b;// member declaration}A;
diizinkan dan berfungsi penuh. Implementasi ini juga memberikan akses ke konversi tipe kompilator dan menghapus beberapa efek penyadap ketika utas eksekusi meninggalkan bidang aplikasi fungsi inisialisasi.
Ini berarti bahwa dalam C typedefs lebih dekat sebagai kelas C ++ daripada struct kesepian.
Sama sekali tidak sulit untuk memiliki struktur referensial sendiri. struct foo {struct foo * berikutnya; hal int; }
Bernd Jendrissek
4
...apa? Mengatakan preprocessor untuk menggambarkan resolusi structsdan typedefs sudah cukup buruk, tetapi sisa tulisan Anda sangat membingungkan sehingga saya merasa kesulitan untuk mendapatkan pesan apa pun darinya. Satu hal yang dapat saya katakan adalah bahwa ide Anda bahwa non- typedefd structtidak dapat dideklarasikan ke depan atau digunakan sebagai anggota yang tidak jelas (pointer) benar-benar salah. Dalam contoh pertama Anda, struct bdapat dengan sepele berisi struct a *, tidak typedefdiperlukan. Pernyataan bahwa structitu hanyalah bagian bodoh dari ekspansi makro, dan itu typedefmemberi mereka kekuatan baru yang revolusioner, sangat keliru
struct * ptr
di dalam struct akan menyebabkan kesalahanJawaban:
Seperti kata Greg Hewgill, typedef berarti Anda tidak perlu lagi menulis di
struct
semua tempat. Itu tidak hanya menyimpan penekanan tombol, itu juga dapat membuat kode lebih bersih karena memberikan sedikit lebih banyak abstraksi.Hal-hal seperti
menjadi lebih bersih ketika Anda tidak perlu melihat kata kunci "struct" di semua tempat, itu terlihat lebih seolah-olah ada jenis yang disebut "Point" dalam bahasa Anda. Yang, setelah itu
typedef
, adalah kasus saya kira.Perhatikan juga bahwa ketika contoh Anda (dan milik saya) mengabaikan penamaan
struct
itu sendiri, sebenarnya penamaan itu juga berguna ketika Anda ingin memberikan jenis buram. Maka Anda akan memiliki kode seperti ini di header, misalnya:dan kemudian memberikan
struct
definisi dalam file implementasi:Dalam kasus yang terakhir ini, Anda tidak dapat mengembalikan Poin dengan nilai, karena definisinya disembunyikan dari pengguna file header. Ini adalah teknik yang digunakan secara luas di GTK + , misalnya.
UPDATE Perhatikan bahwa ada juga proyek-proyek C yang sangat terkenal di mana penggunaan
typedef
untuk menyembunyikanstruct
ini dianggap sebagai ide yang buruk, kernel Linux mungkin adalah proyek yang paling terkenal. Lihat Bab 5 dokumen The Linux Kernel CodingStyle untuk kata-kata marah Linus. :) Maksud saya adalah bahwa "harus" dalam pertanyaan itu mungkin tidak diatur, setelah semua.sumber
Sungguh menakjubkan berapa banyak orang yang melakukan kesalahan ini. TOLONG jangan mengetik struct di C, itu tidak perlu mencemari namespace global yang biasanya sudah sangat tercemar di program C besar.
Juga, struct yang diketik tanpa nama tag adalah penyebab utama pemaksaan hubungan pemesanan yang tidak perlu di antara file header.
Mempertimbangkan:
Dengan definisi seperti itu, tidak menggunakan typedef, adalah mungkin bagi unit compiland untuk memasukkan foo.h untuk mendapatkan
FOO_DEF
definisi tersebut. Jika tidak mencoba untuk melakukan dereferensi anggota 'bar' darifoo
struct maka tidak perlu menyertakan file "bar.h".Juga, karena ruang nama berbeda antara nama tag dan nama anggota, dimungkinkan untuk menulis kode yang sangat mudah dibaca seperti:
Karena ruang nama terpisah, tidak ada konflik dalam penamaan variabel yang bertepatan dengan nama tag struct mereka.
Jika saya harus menjaga kode Anda, saya akan menghapus struct typedef'd Anda.
sumber
typedef struct X { ... } X
. Dengan begitu Anda bisa menggunakan formulir singkatX
untuk membahas struct di mana pun definisi tersedia, tetapi masih dapat meneruskan dan mendeklarasikanstruct X
ketika diinginkan.Dari artikel lama oleh Dan Saks ( http://www.ddj.com/cpp/184403396?pgno=3 ):
Artikel yang ditautkan juga memiliki diskusi tentang bagaimana perilaku C ++ yang tidak memerlukan
typedef
dapat menyebabkan masalah persembunyian nama halus. Untuk mencegah masalah ini, itu ide yang bagus untuktypedef
kelas dan struct Anda di C ++, juga, meskipun pada pandangan pertama tampaknya tidak perlu. Di C ++, dengantypedef
nama bersembunyi menjadi kesalahan yang kompiler memberitahu Anda tentang daripada sumber tersembunyi dari potensi masalah.sumber
int stat(const char *restrict path, struct stat *restrict buf)
fungsi. Di sana Anda memiliki fungsistat
di ruang nama biasa danstruct stat
di ruang nama tag.Menggunakan
typedef
menghindari harus menulisstruct
setiap kali Anda mendeklarasikan variabel jenis itu:sumber
typedef
struktur secara umum. Anda juga bisa melakukannyatypedef struct foo foo;
. Tentu sajastruct
kata kunci tidak diperlukan lebih dari itu yang dapat menjadi petunjuk yang berguna bahwa jenis alias yang kita lihat adalah alias untuk struktur tetapi itu tidak buruk secara umum. Pertimbangkan juga kasus di mana pengenal jenis alias yang dihasilkan daritypedef
menunjukkan bahwa itu adalah alias untuk struktur, fe:typedef struct foo foo_struct;
.Satu alasan bagus lainnya untuk selalu mengetik enum dan struct hasil dari masalah ini:
Perhatikan kesalahan ketik di EnumDef di struct (Enu u mDef)? Ini mengkompilasi tanpa kesalahan (atau peringatan) dan (tergantung pada interpretasi literal dari Standar C) yang benar. Masalahnya adalah bahwa saya baru saja membuat definisi enumerasi (kosong) baru dalam struct saya. Saya tidak (sebagaimana dimaksud) menggunakan definisi EnumDef sebelumnya.
Dengan typdef, kesalahan ketik yang serupa akan menghasilkan kesalahan kompiler untuk menggunakan jenis yang tidak dikenal:
Saya akan menganjurkan SELALU mengetik struct dan enumerasi.
Bukan hanya untuk menyimpan beberapa pengetikan (tidak ada permainan kata-kata yang dimaksudkan;)), tetapi karena lebih aman.
sumber
enum
tipe, karena banyak kompiler memancarkan peringatan aneh ketika menggunakannya 'salah'. Misalnya, menginisialisasi suatuenum
ke 0 mungkin memberikan peringatan 'integer constant not in enum'. Pernyataan ke depanenum
juga tidak diizinkan. Orang harus menggunakanint
(atauunsigned int
) sebagai gantinya.Gaya pengkodean kernel Linux Bab 5 memberikan pro dan kontra (sebagian besar kontra) penggunaan
typedef
.sumber
Ternyata ada pro dan kontra. Sumber informasi yang bermanfaat adalah buku mani "Pemrograman C Pakar" ( Bab 3 ). Secara singkat, di C Anda memiliki beberapa ruang nama: tag, tipe, nama anggota, dan pengidentifikasi .
typedef
memperkenalkan alias untuk suatu jenis dan menempatkannya di tag namespace. Yaitu,mendefinisikan dua hal. Satu Tag di namespace tag dan satu Ketik dalam tipe namespace. Jadi Anda bisa melakukan keduanya
Type myType
danstruct Tag myTagType
. Deklarasi sukastruct Type myType
atauTag myTagType
ilegal. Selain itu, dalam deklarasi seperti ini:kita mendefinisikan pointer ke Tipe kita. Jadi jika kita menyatakan:
kemudian
var1
,var2
danmyTagType1
pointer ke Ketik tetapimyTagType2
tidak.Dalam buku yang disebutkan di atas, disebutkan bahwa struct typedefing tidak terlalu berguna karena hanya menyelamatkan programmer dari menulis kata struct. Namun, saya keberatan, seperti banyak programmer C lainnya. Meskipun kadang-kadang ternyata mengaburkan beberapa nama (itu sebabnya tidak disarankan dalam basis kode besar seperti kernel) ketika Anda ingin menerapkan polimorfisme dalam C, banyak membantu mencari di sini untuk rincian . Contoh:
Anda dapat melakukan:
Jadi, Anda dapat mengakses anggota luar (
flags
) dengan struct bagian dalam (MyPipe
) melalui casting. Bagi saya itu kurang membingungkan untuk melemparkan seluruh jenis daripada melakukan(struct MyWriter_ *) s;
setiap kali Anda ingin melakukan fungsi seperti itu. Dalam kasus ini referensi singkat adalah masalah besar terutama jika Anda menggunakan teknik dalam kode Anda.Akhirnya, aspek terakhir dengan
typedef
tipe ed adalah ketidakmampuan untuk memperpanjangnya, berbeda dengan makro. Jika misalnya, Anda memiliki:Anda kemudian dapat mendeklarasikan
Kami tidak terlalu peduli untuk ini karena struct karena tidak berlaku untuk specifier penyimpanan (
volatile
danconst
).sumber
MyPipe *s; MyWriter *self = (MyWriter *) s;
dan Anda baru saja melanggar alias ketat.typedef struct Tag{ ...members... }Type;
"mendefinisikan dua hal" tidak cukup masuk akal. jika typedef mendefinisikan tag maka 'Ketik' di sini juga harus menjadi tag. Yang benar adalah definisi mendefinisikan 2 tag dan 1 jenis (atau 2 jenis dan 1 tag tidak yakin.):struct Tag
,Tag
DanType
.struct Tag
jelas merupakan suatu tipe.Tag
adalah sebuah tag. tetapi kebingungannya adalah apakahType
sebuah tag atau tipeSaya tidak berpikir deklarasi maju bahkan mungkin dengan typedef. Penggunaan struct, enum, dan union memungkinkan untuk meneruskan deklarasi ketika dependensi (tahu tentang) adalah dua arah.
Style: Penggunaan typedef di C ++ cukup masuk akal. Hampir bisa diperlukan ketika berhadapan dengan templat yang memerlukan banyak dan / atau parameter variabel. Typedef membantu menjaga penamaan tetap lurus.
Tidak demikian halnya dalam bahasa pemrograman C. Penggunaan typedef paling sering tidak memiliki tujuan selain mengaburkan penggunaan struktur data. Karena hanya {struct (6), enum (4), union (5)} jumlah penekanan tombol yang digunakan untuk mendeklarasikan tipe data, hampir tidak ada gunanya untuk alias alias struct. Apakah tipe data itu gabungan atau struktur? Menggunakan deklarasi non-typdefed langsung membuat Anda langsung tahu apa itu.
Perhatikan bagaimana Linux ditulis dengan menghindari ketat dari typedef omong kosong alias ini membawa. Hasilnya adalah gaya minimalis dan bersih.
sumber
struct
mana - mana ... Typedef membuat tipe baru. Apa yang kamu gunakan? Jenis. Kami tidak peduli apakah itu struct, union, atau enum, itu sebabnya kami mengetiknya.FILE
itu?Mari kita mulai dengan dasar-dasar dan terus maju.
Berikut adalah contoh definisi Struktur:
Di sini namanya
point
opsional.Struktur dapat dideklarasikan selama definisi atau setelahnya.
Mendeklarasikan selama definisi
Mendeklarasikan setelah definisi
Sekarang, perhatikan baik-baik kasus terakhir di atas; Anda perlu menulis
struct point
untuk mendeklarasikan Struktur jenis itu jika Anda memutuskan untuk membuat jenis itu di kemudian hari dalam kode Anda.Masukkan
typedef
. Jika Anda bermaksud membuat Struktur baru (Struktur adalah tipe data khusus) di lain waktu di program Anda menggunakan cetak biru yang sama, menggunakantypedef
selama definisi mungkin merupakan ide yang bagus karena Anda dapat menyimpan beberapa pengetikan bergerak maju.Sebuah kata hati-hati saat memberi nama jenis kustom Anda
Tidak ada yang mencegah Anda menggunakan akhiran _t di akhir nama jenis kustom Anda tetapi standar POSIX cadangan penggunaan akhiran _t untuk menunjukkan nama jenis perpustakaan standar.
sumber
nama yang Anda (opsional) berikan kepada struct disebut nama tag dan, seperti yang telah dicatat, bukan tipe itu sendiri. Untuk sampai ke tipe memerlukan awalan struct.
Selain GTK +, saya tidak yakin tagname digunakan seperti biasanya seperti typedef untuk tipe struct, jadi di C ++ yang dikenali dan Anda dapat menghilangkan kata kunci struct dan menggunakan tagname sebagai nama tipe juga:
sumber
typedef tidak akan menyediakan seperangkat struktur data yang saling tergantung. Ini tidak dapat Anda lakukan dengan typdef:
Tentu saja Anda selalu dapat menambahkan:
Apa sebenarnya gunanya itu?
sumber
A> typdef membantu dalam arti dan dokumentasi suatu program dengan memungkinkan pembuatan sinonim yang lebih bermakna untuk tipe data . Selain itu, mereka membantu membuat parameter program terhadap masalah portabilitas (K&R, pg147, C prog lang).
B> suatu struktur mendefinisikan suatu tipe . Structs memungkinkan pengelompokan yang mudah dari kumpulan vars untuk kenyamanan penanganan (K&R, pg127, C prog lang.) Sebagai satu unit
C> mengetikkan struct dijelaskan dalam A di atas.
D> Bagi saya, struct adalah tipe kustom atau wadah atau koleksi atau ruang nama atau tipe kompleks, sedangkan typdef hanyalah sarana untuk membuat lebih banyak nama panggilan.
sumber
Diperlukan mengetikkan C99. Itu sudah usang, tetapi banyak alat (ala HackRank) menggunakan c99 sebagai implementasi C murni. Dan typedef diperlukan di sana.
Saya tidak mengatakan mereka harus berubah (mungkin memiliki dua opsi C) jika persyaratannya berubah, kita yang sedang belajar untuk wawancara di situs adalah SOL.
sumber
typedef
Diperlukan C99 ." Apa maksudmu?C
, bukanC++
. DiC
typedef 'diperlukan' (dan kemungkinan besar akan selalu demikian). 'Diperlukan' seperti pada, Anda tidak akan dapat mendeklarasikan variabelPoint varName;
dan memiliki tipe yang sama denganstruct Point;
tanpatypedef struct Point Point;
.Dalam bahasa pemrograman 'C' kata kunci 'typedef' digunakan untuk mendeklarasikan nama baru untuk beberapa objek (struct, array, function..enum type). Sebagai contoh, saya akan menggunakan 'struct-s'. Dalam 'C' kita sering menyatakan 'struct' di luar fungsi 'utama'. Sebagai contoh:
Setiap kali saya memutuskan untuk menggunakan tipe struct saya akan membutuhkan kata kunci ini 'struct' something '' name '.' Typedef 'hanya akan mengubah nama tipe itu dan saya dapat menggunakan nama baru itu di program saya setiap kali saya mau. Jadi kode kita adalah:
Jika Anda memiliki beberapa objek lokal (struct, array, bernilai) yang akan digunakan di seluruh program Anda, Anda bisa memberinya nama menggunakan 'typedef'.
sumber
Sama sekali, dalam bahasa C, struct / union / enum adalah instruksi makro yang diproses oleh preprocessor bahasa C (jangan salah dengan preprocessor yang memperlakukan "#include" dan lainnya)
jadi:
struct b dikeluarkan sebagai sesuatu seperti ini:
jadi, pada waktu kompilasi, ia berevolusi di stack sebagai sesuatu seperti: b: int ai int i int j
itu juga mengapa sulit untuk memiliki struct selfreferent, putaran preprocessor C dalam loop deklarasi yang tidak dapat diakhiri.
typedef adalah specifier tipe, yang berarti hanya proses compiler C dan itu bisa dilakukan seperti yang dia inginkan untuk mengoptimalkan implementasi kode assembler. Itu juga tidak mengeluarkan anggota tipe par bodoh seperti préprocessor lakukan dengan struct tetapi menggunakan algoritma konstruksi referensi yang lebih kompleks, jadi konstruksi seperti:
diizinkan dan berfungsi penuh. Implementasi ini juga memberikan akses ke konversi tipe kompilator dan menghapus beberapa efek penyadap ketika utas eksekusi meninggalkan bidang aplikasi fungsi inisialisasi.
Ini berarti bahwa dalam C typedefs lebih dekat sebagai kelas C ++ daripada struct kesepian.
sumber
structs
dantypedef
s sudah cukup buruk, tetapi sisa tulisan Anda sangat membingungkan sehingga saya merasa kesulitan untuk mendapatkan pesan apa pun darinya. Satu hal yang dapat saya katakan adalah bahwa ide Anda bahwa non-typedef
dstruct
tidak dapat dideklarasikan ke depan atau digunakan sebagai anggota yang tidak jelas (pointer) benar-benar salah. Dalam contoh pertama Anda,struct b
dapat dengan sepele berisistruct a *
, tidaktypedef
diperlukan. Pernyataan bahwastruct
itu hanyalah bagian bodoh dari ekspansi makro, dan itutypedef
memberi mereka kekuatan baru yang revolusioner, sangat keliru