Typedef e #define são os mesmos em c?

Respostas:

122

Não.

#defineé um token de pré-processador: o próprio compilador nunca o verá.
typedefé um token de compilador: o pré-processador não se importa com isso.

Você pode usar um ou outro para obter o mesmo efeito, mas é melhor usar o adequado para suas necessidades

#define MY_TYPE int
typedef int My_Type;

Quando as coisas ficam "peludas", o uso da ferramenta adequada acerta

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

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
fonte
3
Após o typedef stdfx, objetos válidos desse tipo são ponteiros para funções que recebem um int e não retornam um valor.
Pmc #
1
Por que o #define falha no caso de ponteiro de função como argumento?
Allahjane
2
@ Allahjane: a expansão se torna void fx_def(void (*)(int) fx);; a declaração correta é void fx_def(void (*fx)(int));.
Pmg #
5
Ponteiros de função são factíveis com macros, somente se você está pronto para desistir de sintaxe: #define FX_TYPE(f) void (*f)(int). Você declararia sua função como:void fx_def(FX_TYPE(fx));
plafer
229

typedefobedece a regras de escopo como variáveis, enquanto definepermanece válido até o final da unidade de compilação (ou até uma correspondência undef).

Além disso, algumas coisas podem ser feitas com as typedefquais não podem ser feitas define.
Por exemplo:

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

Não, eles não são os mesmos. Por exemplo:

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

Após o pré-processamento, essa linha se expande para

int* a, b;

Espero que você veja o problema; somente aterá o tipo int *; bserá declarado simples int(porque *está associado ao declarador, não ao especificador de tipo).

Compare isso com

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

Nesse caso, ambos ae bterão tipo int *.

Existem classes inteiras de typedefs que não podem ser emuladas com uma macro de pré-processador, como ponteiros para funções ou matrizes:

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

Tente fazer isso com uma macro de pré-processador.

John Bode
fonte
13

#define define macros.
typedef define tipos.

Agora dizendo isso, aqui estão algumas diferenças:

Com #define, você pode definir constantes que podem ser usadas em tempo de compilação. As constantes podem ser usadas com #ifdef para verificar como o código é compilado e especializar determinado código de acordo com os parâmetros de compilação.
Você também pode usar #define para declarar as funções macro de localização e substituição em miniatura .

O typedef pode ser usado para fornecer aliases aos tipos (o que você provavelmente também poderia fazer com #define ), mas é mais seguro devido à natureza de localização e substituição das constantes #define .
Além disso, você pode usar a declaração de encaminhamento com typedef, que permite declarar um tipo que será usado, mas ainda não está vinculado ao arquivo em que você está escrevendo.

Yochai Timmer
fonte
o que você quer dizer com encontrar e substituir a natureza de #define? , Obrigado
Mohamed El Shenawy
1
Significa antes da compilação, pré-processador vai encontrar todas as macros e substituí-los com sua sintaxe originais
Príncipe Vijay Pratap
"typedef pode ser usado para dar aliases aos tipos" Isso explicou o propósito para mim, obrigado.
Dave Voyles
8

As macros de pré-processador (" #defines") são uma ferramenta de substituição lexical à "pesquisa e substituição". Eles são totalmente independentes da linguagem de programação e não entendem o que você está tentando fazer. Você pode pensar neles como um mecânico glorificado de copiar / colar - ocasionalmente isso é útil, mas você deve usá-lo com cuidado.

Typedefs são um recurso de linguagem C que permite criar aliases para tipos. Isso é extremamente útil para tornar tipos compostos complicados (como estruturas e ponteiros de função) legíveis e manipuláveis ​​(em C ++, existem situações em que você deve digitar um tipo).

Para (3): você sempre deve preferir os recursos de idioma às macros do pré-processador quando isso for possível! Portanto, sempre use typedefs para tipos e valores constantes para constantes. Dessa forma, o compilador pode realmente interagir com você de forma significativa. Lembre-se de que o compilador é seu amigo, portanto, você deve contar o máximo possível. As macros de pré-processador fazem exatamente o contrário, ocultando sua semântica do compilador.

Kerrek SB
fonte
Você pode dizer um exemplo em C ++ onde você deve digitar um tipo? Eu só estou curioso sobre isso.
JYZ
@jyzuz: Há algo se você deseja que uma função membro retorne uma matriz de ponteiros de função, ou algo assim - se você tentar especificar o tipo, o GCC realmente diz "você deve usar um typedef".
30513 Kerrek SB
4

Eles são muito diferentes, embora sejam frequentemente usados ​​para implementar tipos de dados personalizados (que é o que eu estou supondo que essa questão seja).

Como o pmg mencionado, #defineé tratado pelo pré-processador (como uma operação de recortar e colar) antes que o compilador veja o código e typedefseja interpretado pelo compilador.

Uma das principais diferenças (pelo menos quando se trata de definir tipos de dados) é que typedefpermite uma verificação de tipo mais específica. Por exemplo,

#define defType int
typedef int tdType

defType x;
tdType y;

Aqui, o compilador vê a variável x como um int, mas a variável y como um tipo de dados chamado 'tdType' que passa a ter o mesmo tamanho que um int. Se você escreveu uma função que assumiu um parâmetro do tipo defType, o chamador poderia passar um int normal e o compilador não saberia a diferença. Se a função assumisse um parâmetro do tipo tdType, o compilador garantiria que uma variável do tipo apropriado fosse usada durante as chamadas de função.

Além disso, alguns depuradores têm a capacidade de lidar com typedefs, o que pode ser muito mais útil do que ter todos os tipos personalizados listados como seus tipos primitivos subjacentes (como seria se #definefosse usado em vez disso).

bta
fonte
2

Não.
Typedef é uma palavra-chave C que cria um alias para um tipo.
#define é uma instrução de pré-processador, que cria um evento de substituição de texto antes da compilação. Quando o compilador chega ao código, a palavra original "#defined" não está mais lá. #define é usado principalmente para macros e constantes globais.

Travelling Tech Guy
fonte
2
O uso do termo "ponteiro" pode levar a alguma confusão aqui.
Acordado. É por isso que voltei e adicionei um link para o typdef no MSDN - caso alguém no futuro use essa pergunta para descobrir o que é typedef. Mas talvez eu deva mudar essa palavra ...
Traveling Tech Guy
2

AFAIK, No.

typedefajuda a configurar um "alias" para um tipo de dados existente. Por exemplo. typedef char chr;

#defineé uma diretiva de pré - processador usada para definir macros ou substituições gerais de padrão. Por exemplo. #define MAX 100, substitui todas as ocorrências de MAXcom 100

Chris Tang
fonte
0

Como mencionado acima, há uma diferença importante entre #definee typedef. A maneira correta de pensar sobre isso é visualizar um typedef como sendo um tipo "encapsulado" completo. Isso significa que você não pode adicioná-lo depois de o ter declarado.

Você pode estender um nome de tipo de macro com outros especificadores de tipo, mas não um nome de tipo digitado:

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

typedef int fruit;
unsigned fruit i;   // illegal

Além disso, um nome digitado fornece o tipo para cada declarador em uma declaração.

#define fruit int *
fruit apple, banana;

Após a expansão da macro, a segunda linha se torna:

int *apple, banana;

A Apple é um ponteiro para um int, enquanto banana é um int. Em comparação. um typedef como este:

typedef char *fruit;
fruit apple, banana;

declara maçã e banana iguais. O nome na frente é diferente, mas ambos são ponteiros para um caractere.

Paulo
fonte
-1

Como todos disseram acima, eles não são os mesmos. A maioria das respostas indica typedefser mais vantajosa que #define. Mas deixe-me colocar um ponto positivo de #define:
quando seu código é extremamente grande, espalhado por muitos arquivos, é melhor usá-lo #define; ajuda na legibilidade - você pode simplesmente pré-processar todo o código para ver a definição de tipo real de uma variável no local da própria declaração.

abcoep
fonte