Являются ли typedef и #define одинаковыми в c?
Интересно, если typedef
а также #define
одинаковы в с?
11 ответов
Нет.
#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 */
typedef
подчиняется правилам области видимости, как переменные, тогда как define
остается в силе до конца файла (или до совпадения undef
).
Кроме того, некоторые вещи могут быть сделаны с typedef
это не может быть сделано с define
,
Примеры:
typedef int* int_p1;
int_p1 a, b, c; // a, b, and c are all int pointers.
#define int_p2 int*
int_p2 a, b, c; // only the first is a pointer!
,
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
Нет, они не одинаковы. Например:
#define INTPTR int*
...
INTPTR a, b;
После предварительной обработки эта строка расширяется до
int* a, b;
Надеюсь, вы видите проблему; только a
будет иметь тип int *
; b
будет объявлен равниной int
(поскольку *
связан с декларатором, а не спецификатором типа).
Сравните это с
typedef int *INTPTR;
...
INTPTR a, b;
В этом случае оба a
а также b
будет иметь тип int *
,
Существуют целые классы typedef, которые нельзя эмулировать с помощью макроса препроцессора, такие как указатели на функции или массивы:
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
Попробуйте сделать это с помощью макроса препроцессора.
#define определяет макросы.
typedef определяет типы.
Теперь, сказав это, вот несколько отличий:
С помощью #define вы можете определить константы, которые можно использовать во время компиляции. Константы можно использовать с #ifdef, чтобы проверить, как код компилируется, и специализировать определенный код в соответствии с параметрами компиляции.
Вы также можете использовать #define для объявления миниатюрных функций поиска и замены макросов.
typedef может использоваться для присвоения псевдонимов типам (что вы, вероятно, могли бы также сделать с #define), но это безопаснее из-за природы поиска и замены констант #define.
Кроме того, вы можете использовать предварительное объявление с typedef, которое позволяет вам объявить тип, который будет использоваться, но еще не связан с файлом, в который вы пишете.
Макросы препроцессора ("#define
")" - это лексический инструмент замены в стиле "поиск и замена". Они абсолютно не зависят от языка программирования и не понимают, что вы пытаетесь сделать. Вы можете думать о них как о прославленном механике копирования / вставки -- иногда это полезно, но вы должны использовать это с осторожностью.
Typedefs - это функция языка C, которая позволяет создавать псевдонимы для типов. Это чрезвычайно полезно для того, чтобы сделать сложные составные типы (такие как структуры и указатели функций) удобочитаемыми и пригодными для обработки (в C++ есть даже ситуации, когда вы должны вводить определение типа).
Для (3): Вы всегда должны предпочитать языковые возможности макросам препроцессора, когда это возможно! Поэтому всегда используйте typedefs для типов и постоянные значения для констант. Таким образом, компилятор может реально взаимодействовать с вами. Помните, что компилятор - ваш друг, поэтому вы должны рассказать об этом как можно больше. Макросы препроцессора делают прямо противоположное, скрывая семантику от компилятора.
Они очень разные, хотя они часто используются для реализации пользовательских типов данных (и это то, о чем я предполагаю, что весь вопрос в этом).
Как упоминалось в pmg, #define
обрабатывается препроцессором (например, операция вырезания и вставки) до того, как компилятор увидит код, и typedef
интерпретируется компилятором.
Одним из основных отличий (по крайней мере, когда речь идет об определении типов данных) является то, что typedef
позволяет более конкретную проверку типов. Например,
#define defType int
typedef int tdType
defType x;
tdType y;
Здесь компилятор видит переменную x как int, а переменную y как тип данных с именем 'tdType', размер которого совпадает с размером int. Если бы вы написали функцию, которая принимала параметр типа defType, вызывающая сторона могла бы передать нормальное значение типа int, и компилятор не знал бы разницы. Если бы функция вместо этого принимала параметр типа tdType, компилятор гарантировал бы, что переменная правильного типа использовалась во время вызовов функции.
Кроме того, некоторые отладчики имеют возможность обрабатывать typedef
s, что может быть гораздо более полезным, чем перечисление всех пользовательских типов в качестве базовых примитивных типов (как это было бы, если бы #define
был использован вместо).
AFAIK, №
typedef помогает вам установить псевдоним для существующего типа данных. Например, typedef char chr;
#define - это директива препроцессора, используемая для определения макросов или общих шаблонных подстановок. Например, #define MAX 100, заменяет все вхождения MAX на 100
Нет.
typedef - это ключевое слово C, которое создает псевдоним для типа.
#define - это инструкция препроцессора, которая создает событие замены текста перед компиляцией. Когда компилятор добирается до кода, исходного слова "#defined" больше нет. #define в основном используется для макросов и глобальных констант.
Еще одна причина для использования typedef (которая лишь кратко упоминалась в других ответах, но я думаю, что это единственная причина, по которой был создан typedef) — упростить отладку при использовании библиотек с пользовательскими типами. Например, я буду использовать ошибку преобразования типа. Оба приведенных ниже кода будут печатать ошибку времени компиляции, говорящую о том, что char не сравним со строкой, но по-разному.
typedef char letter;
letter el = 'e';
if(el == "hello");
Приведенный выше код напечатает что-то вроде
the variable "el" of type letter (aka "char") is not compatable with type "char*"
#define letter char
letter el = 'e';
if(el == "hello");
Этот код вместо этого напечатает
the variable "el" of type char is not compatable with type "char*"
Это может показаться глупым, потому что я определяю «letter» как «char», но в более сложных библиотеках это может сильно сбивать с толку, потому что указатели на такие объекты, как кнопки, окна, звуковые серверы, изображения и множество других вещей определяются как
unsigned char *
, который можно было бы отлаживать точно так же, как и при использовании метода #define.
Как упоминалось выше, есть ключевое различие между #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;
заявляет, что яблоко и банан одно и то же. Имя на лицевой стороне отличается, но оба они указывают на символ.
Как все говорили выше, они не одинаковы. Большинство ответов указывают typedef
быть более выгодным, чем #define
, Но позвольте мне поставить плюс #define
:
когда ваш код очень большой, разбросан по многим файлам, лучше использовать #define
; это помогает в удобочитаемости - вы можете просто предварительно обработать весь код, чтобы увидеть фактическое определение типа переменной в месте ее объявления.