¿Son typedef y #define lo mismo en c?

Respuestas:

122

No.

#define es un token de preprocesador: el compilador en sí nunca lo verá.
typedefes un token compilador: al preprocesador no le importa.

Puede usar uno u otro para lograr el mismo efecto, pero es mejor usar el adecuado para sus necesidades

#define MY_TYPE int
typedef int My_Type;

Cuando las cosas se ponen "peludas", usar la herramienta adecuada lo hace correcto

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

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
fuente
3
Después de typedef stdfx, los objetos válidos de ese tipo son punteros a funciones que reciben un int y no devuelven un valor.
pmg
1
¿Por qué fallaría el #define en casec del puntero de función como argumento?
Allahjane
2
@Allahjane: la expansión se hace void fx_def(void (*)(int) fx);; La declaración correcta es void fx_def(void (*fx)(int));.
pmg
55
Punteros de función son factibles con macros, sólo si estás dispuesto a renunciar a la sintaxis: #define FX_TYPE(f) void (*f)(int). Luego declararía su función como:void fx_def(FX_TYPE(fx));
jugador el
229

typedefobedece las reglas de alcance al igual que las variables, mientras que definepermanece válido hasta el final de la unidad de compilación (o hasta una coincidencia undef).

Además, se pueden hacer algunas cosas con las typedefque no se puede hacer define.
Por ejemplo:

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
fuente
23

No, no son lo mismo. Por ejemplo:

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

Después del preprocesamiento, esa línea se expande a

int* a, b;

Espero que veas el problema; solo atendrá el tipo int *; bse declarará sin formato int(porque *está asociado con el declarador, no con el especificador de tipo).

Contrasta eso con

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

En este caso, tanto ay btendrá tipo int *.

Hay clases enteras de typedefs que no se pueden emular con una macro de preprocesador, como punteros a funciones o matrices:

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

Intenta hacerlo con una macro de preprocesador.

John Bode
fuente
13

#define define macros.
typedef define tipos.

Ahora diciendo eso, aquí hay algunas diferencias:

Con #define puedes definir constantes que se pueden usar en tiempo de compilación. Las constantes se pueden usar con #ifdef para verificar cómo se compila el código y especializar cierto código de acuerdo con los parámetros de compilación.
También puede usar #define para declarar funciones macro de buscar y reemplazar en miniatura .

typedef se puede usar para dar alias a los tipos (lo que probablemente también podría hacer con #define ), pero es más seguro debido a la naturaleza de búsqueda y reemplazo de #define constantes.
Además de eso, puede usar la declaración hacia adelante con typedef que le permite declarar un tipo que se usará, pero que aún no está vinculado al archivo en el que está escribiendo.

Yochai Timmer
fuente
¿Qué quieres decir con buscar y reemplazar la naturaleza de #define? , Gracias
Mohamed El Shenawy
1
Significa que antes de la compilación, el preprocesador encontrará todas las macros y las reemplazará con su sintaxis original
Prince Vijay Pratap
"typedef se puede usar para dar alias a los tipos" Esto explicó el propósito para mí, gracias.
Dave Voyles
8

Las macros de preprocesador (" #define's") son una herramienta de reemplazo léxico a la "búsqueda y reemplazo". Son completamente agnósticos del lenguaje de programación y no entienden lo que estás tratando de hacer. Puede pensar en ellos como una mecánica glorificada de copiar / pegar; en ocasiones es útil, pero debe usarla con cuidado.

Typedefs es una característica del lenguaje C que le permite crear alias para los tipos. Esto es extremadamente útil para hacer que los tipos compuestos complicados (como estructuras y punteros de función) sean legibles y manejables (en C ++ incluso hay situaciones en las que debe escribir typedef a type).

Para (3): ¡siempre debe preferir las características del lenguaje a las macros de preprocesador! Por lo tanto, use siempre typedefs para tipos y valores constantes para constantes. De esa manera, el compilador puede interactuar contigo significativamente. Recuerde que el compilador es su amigo, por lo que debe contarlo tanto como sea posible. Las macros de preprocesador hacen exactamente lo contrario al ocultar su semántica del compilador.

Kerrek SB
fuente
¿Puedes decir un ejemplo en C ++ donde debes escribirdef un tipo? Solo tengo curiosidad por eso.
jyz
@jyzuz: Hay algo si desea que una función miembro devuelva una matriz de punteros de función, o algo así: si intenta deletrear el tipo, GCC realmente dice "debe usar un typedef".
Kerrek SB
4

Son muy diferentes, aunque a menudo se usan para implementar tipos de datos personalizados (que es de lo que supongo que se trata esta pregunta).

Como se mencionó pmg, #defineel preprocesador lo maneja (como una operación de cortar y pegar) antes de que el compilador vea el código, y typedefel compilador lo interpreta.

Una de las principales diferencias (al menos cuando se trata de definir tipos de datos) es que typedefpermite una verificación de tipos más específica. Por ejemplo,

#define defType int
typedef int tdType

defType x;
tdType y;

Aquí, el compilador ve la variable x como int, pero la variable y como un tipo de datos llamado 'tdType' que resulta ser del mismo tamaño que un int. Si escribió una función que tomara un parámetro de tipo defType, la persona que llama podría pasar un int normal y el compilador no notaría la diferencia. Si la función en su lugar tomó un parámetro de tipo tdType, el compilador se aseguraría de que se utilizara una variable del tipo adecuado durante las llamadas de función.

Además, algunos depuradores tienen la capacidad de manejar typedefs, lo que puede ser mucho más útil que tener todos los tipos personalizados listados como sus tipos primitivos subyacentes (como lo sería si #definese usara en su lugar).

bta
fuente
2

No.
typedef es una palabra clave C que crea un alias para un tipo.
#define es una instrucción previa al procesador, que crea un evento de reemplazo de texto antes de la compilación. Cuando el compilador llega al código, la palabra original "#definida" ya no está allí. #define se usa principalmente para macros y constantes globales.

Travelling Tech Guy
fuente
2
El uso del término "puntero" podría generar cierta confusión aquí.
Convenido. Es por eso que volví y agregué un enlace a typdef en MSDN, en caso de que alguien en el futuro use esta pregunta para encontrar qué es typedef. Pero tal vez debería cambiar esa palabra ...
Travelling Tech Guy el
2

AFAIK, No.

typedefle ayuda a configurar un "alias" para un tipo de datos existente. Por ej. typedef char chr;

#definees una directiva de preprocesador utilizada para definir macros o sustituciones de patrones generales. Por ej. #define MAX 100, sustituye todas las apariciones de MAXcon 100

Chris Tang
fuente
0

Como se mencionó anteriormente, hay una diferencia clave entre #define y typedef. La forma correcta de pensar en eso es ver un typedef como un tipo "encapsulado" completo. Significa que no puede agregarlo después de haberlo declarado.

Puede ampliar un nombre de tipo de macro con otros especificadores de tipo, pero no un nombre de tipo definido por tipo:

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

typedef int fruit;
unsigned fruit i;   // illegal

Además, un nombre typedef'd proporciona el tipo para cada declarante en una declaración.

#define fruit int *
fruit apple, banana;

Después de la expansión macro, la segunda línea se convierte en:

int *apple, banana;

Apple es un puntero a un int, mientras que banana es un int. En comparación. un typedef como este:

typedef char *fruit;
fruit apple, banana;

declara que tanto la manzana como el plátano son iguales. El nombre en el frente es diferente, pero ambos son indicadores de un personaje.

Pablo
fuente
-1

Como todos dijeron anteriormente, no son lo mismo. La mayoría de las respuestas indican typedefser más ventajosas que #define. Pero permítanme poner un punto positivo #define:
cuando su código es extremadamente grande, disperso en muchos archivos, es mejor usarlo #define; ayuda en la legibilidad: simplemente puede preprocesar todo el código para ver la definición de tipo real de una variable en el lugar de su declaración.

abcoep
fuente