typedef küçük bir şey yapar: zaten var olan bir tipe başka bir isim verir. Yeni bir tip oluşturulmaz, bellek ayrılmaz ve değerin nasıl davrandığıyla ilgili hiçbir şey değişmez. Bir adlandırma aracıdır - ve yerleşik tip adlarının uzadığı C'de (unsigned long long, struct Employee, void (*)(int)) iyi bir isim çok şey değer.
Temel Biçim
Söz dizimi, başına typedef eklenmiş bir değişken bildirimi gibi okunur. Değişken adının geleceği yere yeni tip adını koyarsınız:
unsigned long count; // count adında bir değişken bildirir
typedef unsigned long ulong; // ulong adında bir TİP bildirir
Kuralın tamamı budur ve bu sayfanın ilerisindeki tuhaf görünenler dahil okuyacağınız her typedef'i açıklar.
Celsius/Fahrenheit çiftinin size kazandırmadığı şeye dikkat edin: tür güvenliği. İkisi de yalnızca double'dır, dolayısıyla Celsius beklenen yere bir Fahrenheit değeri geçirmek memnuniyetle derlenir. İsimler niyeti insanlar için belgeler; bir denetim oluşturmazlar.
typedef struct Deyimi
Çoğu C programının bir typedef içermesinin asıl sebebi budur. C'de bir yapının tip adı anahtar kelimeyi içerir:
struct Point { int x; int y; };
struct Point p; /* her seferinde "struct" kelimesi */
Bir typedef bunu kısaltır:
Onu önceki kuralla okuyun: typedef'i çıkarın, elinizde struct Point {...} Point; kalır ki bu Point adında bir değişkenin bildirimidir. typedef'i geri ekleyin ve Point bunun yerine bir tip adı olur.
Etiketli ya da Etiketsiz
Etiketi tamamen dışarıda bırakabilirsiniz; bu, yalnızca typedef adına sahip isimsiz bir yapı verir:
typedef struct {
int x;
int y;
} Point; /* "struct Point" yoktur - yalnızca "Point" */
Bu daha derli topludur ve düz bir veri kaydı için yaygın tarzdır. Ama yapının kendisinden söz etmesi gerektiği anda başarısız olur, çünkü typedef adı kendi bildirimi bitene dek kullanılabilir değildir:
/* DERLENMEZ: "Node", kendi süslü parantezlerinin içinde henüz bir tip değil. */
typedef struct {
int value;
Node *next;
} Node;
Etiketi koruyun, kendine atıf çalışır, çünkü struct Node etiket görülür görülmez kullanılabilir:
Pratik kural: etiketi koruyun. Bir kelimeye mal olur, typedef adıyla eşleşir dolayısıyla hiçbir şey kafa karıştırıcı değildir ve kendine atıf ile başlıklardaki ileri bildirimler için kapıyı açık bırakır. O bağlı düğümün neye dönüştüğü için bkz. yapılar ve göstericiler.
İleri Bildirimler ve Opak Tipler
Bir yapıya giden göstericinin, yapının içeriği bilinmese bile bilinen bir boyutu olduğu için, bir başlık üyelerini açığa çıkarmadan bir tip dağıtabilir:
/* stack.h */
typedef struct Stack Stack; /* bildirildi, tanımlanmadı */
Stack *stack_create(void);
void stack_push(Stack *s, int value);
int stack_pop(Stack *s);
void stack_destroy(Stack *s);
Tam struct Stack { ... };, stack.c içinde yaşar ve dışarıdan hiç kimse üyelerine dokunamaz. Bu opak tip kalıbı, C kütüphanelerinin kapsüllemeyi uygulama yoludur ve standart kütüphanedeki FILE tam olarak budur - fopen'dan bir FILE * alırsınız ve içinde ne olduğu hakkında size hiçbir şey söylenmez. Bkz. dosya işlemleri.
enum'lar ve union'lar için typedef
Aynı deyim diğer iki bileşik tür için de geçerlidir:
typedef olmadan bunlar enum Color c; ve union Number n; olurdu. Gerçekte ne yaptıkları için bkz. enum'lar ve birleşimler.
Bir Fonksiyon Göstericisi için typedef
typedef'in bir kolaylık olmaktan çıkıp neredeyse zorunlu hâle geldiği yer burasıdır. Bir fonksiyon göstericisinin ham söz dizimi meşhur biçimde zor okunur:
void (*handler)(int, const char *); /* bir değişken */
void register_cb(void (*cb)(int, const char *)); /* bir parametre */
Tipi bir kez adlandırın, ikisi de okunaklı olsun:
typedef'i çıkarma kuralını yeniden uygulayın: tek başına int (*IntBinaryOp)(int, int);, iki int alıp bir int döndüren bir fonksiyonu gösteren IntBinaryOp adında bir değişken bildirirdi. typedef ile bu, tipin adı olur. Daha fazlası fonksiyon göstericileri sayfasında.
typedef ile #define
Basit takma adlar için birbirinin yerine geçebilir görünürler ve değildirler:
#define INT_PTR int *
typedef int *int_ptr;
INT_PTR a, b; /* şuna genişler: int *a, b; -- b düz bir int! */
int_ptr c, d; /* hem c hem d birer int * */
#define, derleyici kodu görmeden önce yapılan kör metin değiştirmedir; typedef, derleyicinin anladığı gerçek bir bildirimdir ve listedeki her isme uygulanır. Tipler için typedef kullanın ve #define'ı sabitlere ve makrolara ayırın.
Bir typedef Ne Zaman Zarar Verir
Typedef'ler okuyucunun ihtiyaç duyduğu bilgiyi de gizleyebilir. En keskin örnek bir göstericiyi gizlemektir:
typedef struct Node *NodeRef; /* yıldız yok olur */
NodeRef n = get_node();
NodeRef n'e bakan bir okuyucu, n'in NULL olup olamayacağını, serbest bırakılması gerekip gerekmediğini, n ile onun bir kopyasının aynı nesneyi paylaşıp paylaşmadığını ya da üyelere . ile mi -> ile mi ulaşılacağını anlayamaz. Dört sorunun dördü de struct Node *n ile anında yanıtlanır.
Standart kütüphane de aynı fikirde: yapıyı typedef eder (FILE) ve yıldızı kullanım noktasında bırakır (FILE *fp). Bundan iki makul rehber çıkar:
- Yapıları, birleşimleri, enum'ları ve fonksiyon göstericilerini typedef edin - kaldırılan gürültü hiçbir bilgi taşımaz.
- Yalnızca kısaltmak için bir göstericiyi typedef etmeyin ve temel bir tipi gizlemek için typedef etmeyin (
typedef int Boolean;, birini içine7saklamaya davet eder - bunun yerine booleanlar sayfasında ele alınan<stdbool.h>'dekibool'u kullanın).
Standart kütüphanenin <stdint.h> içindeki kendi sabit genişlikli isimleri (uint32_t, int64_t, size_t) hepsi typedef'tir ve bu özellik için en iyi gerekçedir: tam olarak ne olduklarını söylerler, taşınabilirdirler ve hiçbir şey gizlenmez.
Sıkça Sorulan Sorular
C'de typedef ne yapar?
Var olan bir tipe ikinci bir isim verir. typedef unsigned long ulong;, o andan itibaren ulong ile unsigned long'un aynı tip olduğu anlamına gelir. Yeni bir tip ya da yeni bir depolama oluşturmaz - yalnızca zaten sahip olduğunuz bir tipi yazmanın daha kısa ya da daha açıklayıcı bir yolunu verir.
C'de typedef struct deyimi nedir?
typedef struct Point { int x; int y; } Point;, yapıyı bildirir ve tipi tek bir deyimde Point diye adlandırır, böylece struct Point p; yerine Point p; yazabilirsiniz. Etiketi (struct Point) korumak, bir bağlı liste düğümü gibi yapının kendisine atıfta bulunması gerektiğinde önemlidir.
typedef ile #define arasındaki fark nedir?
typedef derleyici tarafından işlenir ve gerçek bir tip takma adı oluşturur; #define, derlemeden önce ön işlemci tarafından yapılan bir metin değiştirmedir. O fark göstericilerde canınızı yakar: #define PTR int*, PTR a, b;'yi int* a, b;'ye genişletir - yalnızca a bir göstericidir. typedef int *PTR; ikisini de gösterici yapar.
C'de bir gösterici tipini typedef etmeli miyim?
Genellikle hayır. typedef struct Node *NodeRef;, tipin bir gösterici olduğunu gizler, dolayısıyla okuyucular bir değişkenin NULL olabilir mi, serbest bırakılmalı mı ya da -> mı gerektiriyor anlayamaz. Standart kütüphanenin FILE *'ı yıldızı tam olarak bu sebeple görünür tutar. Ona giden göstericiyi değil, yapıyı typedef edin.