Являются ли 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 */
PMG
источник
3
После определения типа stdfxдопустимые объекты этого типа являются указателями на функции, которые получают int и не возвращают значение.
pmg
1
Почему #define не сработает в случае использования указателя функции в качестве аргумента?
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и bбудут иметь тип int *.

Есть целые классы определений типов, которые нельзя эмулировать с помощью макроса препроцессора, например указатели на функции или массивы:

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"? , Спасибо
Мохамед Эль Шенави
1
Это означает, что перед компиляцией препроцессор найдет все макросы и заменит их исходным синтаксисом
Принц Виджай Пратап
"typedef может использоваться для присвоения псевдонимов типам" Это объяснило мне цель, спасибо.
Дэйв Войлс
8

Макросы препроцессора (« #defines») - это инструмент лексической замены типа «поиск и замена». Они совершенно не зависят от языка программирования и не понимают, что вы пытаетесь сделать. Вы можете думать о них как о прославленном механизме копирования / вставки - иногда это полезно, но вы должны использовать его с осторожностью.

Typedefs - это функция языка C, которая позволяет создавать псевдонимы для типов. Это чрезвычайно полезно для того, чтобы сделать сложные составные типы (например, структуры и указатели функций) удобочитаемыми и управляемыми (в C ++ есть даже ситуации, когда вы должны ввести тип).

Для (3): вы всегда должны предпочесть языковые функции макросам препроцессора, когда это возможно! Поэтому всегда используйте typedef для типов и постоянные значения для констант. Таким образом, компилятор действительно сможет осмысленно взаимодействовать с вами. Помните, что компилятор - ваш друг, поэтому вы должны рассказать ему как можно больше. Макросы препроцессора делают прямо противоположное, скрывая вашу семантику от компилятора.

Керрек С.Б.
источник
Можете ли вы назвать один пример на C ++, где вы должны ввести тип? Мне просто любопытно об этом.
jyz
@jyzuz: Есть что-то, если вы хотите, чтобы функция-член возвращала массив указателей на функции или что-то в этом роде - если вы попытаетесь указать тип, GCC на самом деле скажет «вы должны использовать typedef».
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 в основном используется для макросов и глобальных констант.

Путешественник Tech Guy
источник
2
Использование термина «указатель» может привести здесь к некоторой путанице.
Согласовано. Вот почему я вернулся и добавил ссылку на typdef в MSDN - на всякий случай, если кто-нибудь в будущем будет использовать этот вопрос, чтобы узнать, что такое typedef. Но, может быть, мне стоит изменить это слово ...
Traveling Tech Guy
2

AFAIK, Нет.

typedefпомогает вам установить «псевдоним» для существующего типа данных. Например, typedef char chr;

#define- это директива препроцессора, используемая для определения макросов или общих замен шаблонов. Например, #define MAX 100, заменяет все вхождения на MAX100

Крис Танг
источник
0

Как упоминалось выше, существует ключевое различие между #defineи typedef. Правильный способ думать об этом - рассматривать typedef как полный «инкапсулированный» тип. Это означает, что вы не можете добавлять к нему после того, как вы его объявили.

Вы можете расширить имя типа макроса другими спецификаторами типа, но не именем типа, определяемым по типу:

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

typedef int fruit;
unsigned fruit i;   // illegal

Кроме того, имя typedef'd предоставляет тип для каждого декларатора в объявлении.

#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; это помогает в удобочитаемости - вы можете просто предварительно обработать весь код, чтобы увидеть фактическое определение типа переменной в месте ее объявления.

abcoep
источник