Czy typedef i #define to to samo w c?

Odpowiedzi:

122

Nie.

#definejest tokenem preprocesora: sam kompilator nigdy go nie zobaczy.
typedefjest tokenem kompilatora: preprocesor nie dba o to.

Możesz użyć jednego lub drugiego, aby osiągnąć ten sam efekt, ale lepiej użyć odpowiedniego dla swoich potrzeb

#define MY_TYPE int
typedef int My_Type;

Kiedy robi się „owłosiona”, użycie odpowiedniego narzędzia naprawia to

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

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
źródło
3
Po typedef stdfxprawidłowe obiekty tego typu są wskaźnikami do funkcji, które otrzymują int i nie zwracają wartości.
pmg,
1
Dlaczego #define miałoby się nie powieść w przypadku wskaźnika funkcji jako argumentu?
Allahjane
2
@Allahjane: ekspansja staje się void fx_def(void (*)(int) fx);; prawidłowa deklaracja to void fx_def(void (*fx)(int));.
pmg
5
Wskaźniki funkcyjne są wykonalne z makrami, tylko jeśli jesteś gotów zrezygnować składni: #define FX_TYPE(f) void (*f)(int). Następnie zadeklarowałbyś swoją funkcję jako:void fx_def(FX_TYPE(fx));
plafer
229

typedefprzestrzega reguł określania zakresu tak samo jak zmienne, ale definepozostaje ważna do końca jednostki kompilacji (lub do dopasowania undef).

Ponadto można zrobić z typedeftym pewne rzeczy , których nie można zrobić define.
Na przykład:

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
źródło
23

Nie, to nie to samo. Na przykład:

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

Po wstępnym przetworzeniu ta linia rozwija się do

int* a, b;

Miejmy nadzieję, że widzisz problem; tylko abędzie miał typ int *; bzostanie zadeklarowany jako zwykły int(ponieważ *jest skojarzony z deklaratorem, a nie specyfikatorem typu).

Porównaj to z

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

W takim przypadku oba ai bbędą miały typ int *.

Istnieją całe klasy typedef, których nie można emulować za pomocą makra preprocesora, na przykład wskaźniki do funkcji lub tablic:

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

Spróbuj to zrobić za pomocą makra preprocesora.

John Bode
źródło
13

#define definiuje makra.
typedef definiuje typy.

Mówiąc to, oto kilka różnic:

Za pomocą #define możesz zdefiniować stałe, które mogą być używane w czasie kompilacji. Stałe mogą być używane z #ifdef, aby sprawdzić, jak kod jest kompilowany, i specjalizować określony kod zgodnie z parametrami kompilacji.
Możesz także użyć #define, aby zadeklarować miniaturowe funkcje makra znajdź i zamień .

typedef może służyć do nadawania aliasów typom (co prawdopodobnie można by zrobić również za pomocą #define ), ale jest to bezpieczniejsze ze względu na naturę #define typu znajdź i zamień .
Poza tym możesz użyć deklaracji forward z typedef, która pozwala zadeklarować typ, który będzie używany, ale nie jest jeszcze powiązany z plikiem, w którym piszesz.

Yochai Timmer
źródło
co masz na myśli mówiąc o znajdowaniu i zastępowaniu natury #define? , Dziękuję
Mohamed El Shenawy
1
Oznacza to, że przed kompilacją preprocesor znajdzie wszystkie makra i zastąpi je ich oryginalną składnią
Prince Vijay Pratap
„Typedef może służyć do nadawania aliasów typom” To wyjaśniło mi cel, dzięki.
Dave Voyles
8

Makra preprocesora („ #defines”) są leksykalnym narzędziem zastępującym a la „wyszukaj i zamień”. Są całkowicie agnostykami języka programowania i nie rozumieją, co próbujesz zrobić. Możesz myśleć o nich jako o chwalebnym mechanizmie kopiowania / wklejania - czasami jest to przydatne, ale powinieneś używać go ostrożnie.

Typedef to funkcja języka C, która umożliwia tworzenie aliasów dla typów. Jest to niezwykle przydatne, aby skomplikowane typy złożone (takie jak struktury i wskaźniki funkcji) były czytelne i obsługiwane (w C ++ są nawet sytuacje, w których trzeba wpisać typ).

Dla (3): Zawsze powinieneś preferować funkcje językowe od makr preprocesora, kiedy jest to możliwe! Dlatego zawsze używaj typedef dla typów i stałych wartości dla stałych. W ten sposób kompilator może faktycznie współdziałać z Tobą. Pamiętaj, że kompilator jest twoim przyjacielem, więc powinieneś mu powiedzieć jak najwięcej. Makra preprocesora działają dokładnie odwrotnie, ukrywając semantykę przed kompilatorem.

Kerrek SB
źródło
Czy możesz powiedzieć jeden przykład w C ++, w którym należy wpisać typ? Jestem tego po prostu ciekawy.
jyz
@jyzuz: Jest coś, jeśli chcesz, aby funkcja składowa zwracała tablicę wskaźników funkcji, lub coś w tym stylu - jeśli spróbujesz przeliterować typ, GCC faktycznie mówi "musisz użyć typedef".
Kerrek SB
4

Są bardzo różne, chociaż często są używane do implementacji niestandardowych typów danych (i zakładam, że o to chodzi w tym pytaniu).

Jak wspomniano, pmg #definejest obsługiwany przez preprocesor (podobnie jak operacja wycinania i wklejania), zanim kompilator zobaczy kod, itypedef jest interpretowany przez kompilator.

Jedną z głównych różnic (przynajmniej jeśli chodzi o definiowanie typów danych) jest to, że typedefumożliwia bardziej szczegółowe sprawdzanie typów. Na przykład,

#define defType int
typedef int tdType

defType x;
tdType y;

Tutaj kompilator widzi zmienną x jako int, ale zmienną y jako typ danych o nazwie „tdType”, który ma taki sam rozmiar jak int. Jeśli napisałeś funkcję, która przyjęłaby parametr typu defType, wywołujący mógłby przekazać normalną wartość int, a kompilator nie znałby różnicy. Gdyby zamiast tego funkcja przyjęła parametr typu tdType, kompilator zapewni, że podczas wywołań funkcji zostanie użyta zmienna odpowiedniego typu.

Ponadto niektóre debugery mają możliwość obsługi typedefs, co może być znacznie bardziej przydatne niż umieszczanie wszystkich typów niestandardowych na liście jako ich podstawowe typy pierwotne (tak jakby #definebył używany zamiast tego).

bta
źródło
2

Nie.
Typedef to słowo kluczowe C, które tworzy alias dla typu.
#define to instrukcja preprocesora, która tworzy zdarzenie zamiany tekstu przed kompilacją. Gdy kompilator dotrze do kodu, oryginalne słowo „#defined” już nie istnieje. #define jest używany głównie w przypadku makr i stałych globalnych.

Podróżujący Technik
źródło
2
Użycie terminu „wskaźnik” może tu wprowadzić pewne zamieszanie.
Zgoda. Dlatego wróciłem i dodałem link do typdef na MSDN - na wypadek, gdyby ktoś w przyszłości użył tego pytania, aby dowiedzieć się, czym jest typedef. Ale może powinienem zmienić to słowo ...
Traveling Tech Guy
2

AFAIK, No.

typedefpomaga ustawić „alias” do istniejącego typu danych. Np. typedef char chr;

#define jest dyrektywą preprocesora używaną do definiowania makr lub ogólnych podstawień wzorców. Np. #define MAX 100, zastępuje wszystkie wystąpienia MAX100

Chris Tang
źródło
0

Jak wspomniano powyżej, istnieje kluczowa różnica między #define i typedef. Właściwy sposób, aby o tym pomyśleć, to zobaczyć typedef jako kompletny typ „hermetyzowany”. Oznacza to, że po zadeklarowaniu nie możesz do niego nic dodawać.

Możesz rozszerzyć nazwę typu makra o inne specyfikatory typu, ale nie o nazwę typu zdefiniowaną przez typ:

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

typedef int fruit;
unsigned fruit i;   // illegal

Ponadto nazwa typedef'd zapewnia typ dla każdego deklaratora w deklaracji.

#define fruit int *
fruit apple, banana;

Po rozwinięciu makra druga linia staje się:

int *apple, banana;

Apple jest wskaźnikiem do int, a banan to int. W porównaniu. taki typ:

typedef char *fruit;
fruit apple, banana;

deklaruje, że jabłko i banan są takie same. Nazwa na przodzie jest inna, ale oba są wskazówkami do znaku.

Paweł
źródło
-1

Jak wszyscy powiedzieli powyżej, nie są tacy sami. Większość odpowiedzi wskazuje, typedefże są one bardziej korzystne niż #define. Ale pozwólcie, że dodam plus #define:
kiedy twój kod jest bardzo duży, rozproszony w wielu plikach, lepiej go użyć #define; pomaga w czytelności - możesz po prostu wstępnie przetworzyć cały kod, aby zobaczyć rzeczywistą definicję typu zmiennej w miejscu jej deklaracji.

abcoep
źródło