C typedef
O typedef (de type definition, "definição de tipo") dá um apelido a um tipo que já existe. Com ele, struct Aluno pode virar só Aluno, e um double que guarda dinheiro pode se chamar Dinheiro. Ele não cria nada de novo na memória e não muda o que o programa faz: só deixa o código mais curto e mais fácil de ler. Você já usou vários typedef sem saber: size_t, FILE e int32_t são apelidos criados assim, dentro dos cabeçalhos da biblioteca.
- A criar um apelido com
typedef tipo Apelido;. - Por que o apelido não é um tipo novo, e o que isso deixa passar.
- As três formas de usar
typedefcomstruct, e qual escolher. - Como escrever uma struct que aponta para ela mesma (o erro
unknown type name). - Por que não esconder um ponteiro num typedef, e por que
typedefé melhor que#definepara tipos. - De onde vêm
size_t,FILEeint32_t, e o que quer dizer o_t.
Esta aula supõe que você já leu Structs e Structs e Ponteiros. Todos os programas foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c/td, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.
A ideia: o apelido
Na escola da Ana, o professor de matemática se chama José Carlos de Oliveira, mas todo mundo o chama de Zé. "Zé" não é outra pessoa: é o mesmo professor, com um nome mais curto. Quem o chama de "Zé" e quem o chama de "José Carlos" está falando dele do mesmo jeito, e ninguém precisa avisar a secretaria.
O typedef é isso para os tipos: typedef struct Aluno Aluno; diz ao compilador "quando eu escrever Aluno, entenda struct Aluno". O tipo é o mesmo; só ganhou um nome a mais.
| Na escola | Em C |
|---|---|
| O nome completo: José Carlos de Oliveira | O tipo original: struct Aluno, double, unsigned long |
| O apelido: Zé | O nome do typedef: Aluno, Dinheiro, size_t |
| "Zé" e "José Carlos" são a mesma pessoa | O apelido e o original são o mesmo tipo: dá para misturar à vontade |
1. O primeiro typedef
A lojinha da Ana guarda preços em double. Para deixar claro, no código, quais double são dinheiro, ela cria um apelido:
#include <stdio.h>
typedef double Dinheiro;
int main(void) {
Dinheiro preco = 19.90;
Dinheiro desconto = 2.50;
double pago = preco - desconto;
printf("Preço: R$ %.2f\n", preco);
printf("Pago: R$ %.2f\n", pago);
printf("sizeof(Dinheiro) = %zu, sizeof(double) = %zu\n",
sizeof(Dinheiro), sizeof(double));
return 0;
}
- typedef double Dinheiro;
- A forma é
typedef+ o tipo que já existe + o apelido novo +;. Um jeito de lembrar: escreva uma declaração de variável comum (double Dinheiro;) e ponhatypedefna frente. O que seria o nome da variável vira o nome do tipo. Fica fora das funções, no começo do arquivo, para valer no arquivo todo. - Dinheiro preco = 19.90;
- Daqui em diante,
Dinheiropode ser usado em qualquer lugar onde caberiadouble: variáveis, parâmetros, retorno de funções,sizeof. - double pago = preco - desconto;
- Misturar
Dinheiroedoubleé permitido, sem conversão nenhuma: é o mesmo tipo. - %.2f
- O
printfnem sabe que existeDinheiro: para ele é umdouble, e o formato continua sendo o dodouble.
$ gcc -std=c23 -Wall -Wextra dinheiro.c -o dinheiro $ ./dinheiro Preço: R$ 19.90 Pago: R$ 17.40 sizeof(Dinheiro) = 8, sizeof(double) = 8
Os dois sizeof dão 8: Dinheiro é um double, byte por byte. A vantagem aparece no dia em que a Ana decidir guardar os preços em centavos, num long long: ela muda uma linha (typedef long long Dinheiro;) em vez de caçar quais dos double do programa eram dinheiro. (Os %.2f também teriam de mudar; o typedef não resolve tudo.)
O apelido não protege nada
Como o apelido é o mesmo tipo, o compilador não reclama se você trocar um pelo outro. A Ana criou dois apelidos para int:
#include <stdio.h>
typedef int Idade;
typedef int Ano;
void fazer_aniversario(Idade *idade) {
(*idade)++;
}
int main(void) {
Idade ana = 29;
Ano hoje = 2026;
fazer_aniversario(&ana);
fazer_aniversario(&hoje);
printf("Ana tem %d anos; estamos em %d.\n", ana, hoje);
return 0;
}
$ gcc -std=c23 -Wall -Wextra mistura.c -o mistura « nenhum aviso $ ./mistura Ana tem 30 anos; estamos em 2027.
O fazer_aniversario(&hoje) é claramente um engano (o ano fez aniversário?), mas Ano * e Idade * são os dois int *, e nem o gcc nem o Clang avisam. O typedef serve para documentar a intenção para quem lê, não para o compilador conferir. Se você quiser que o compilador barre a mistura, embrulhe o valor numa struct (typedef struct { int valor; } Ano;): duas structs diferentes nunca se misturam.
2. typedef com struct
Este é o uso mais comum. Em C, o nome do tipo de uma struct são duas palavras: struct Aluno (aula Structs). Com um typedef, vira uma só. Dá para escrever a struct e o apelido de uma vez:
#include <stdio.h>
typedef struct Aluno {
char nome[30];
double nota;
} Aluno;
void mostrar(const Aluno *a) {
printf("%s: %.1f\n", a->nome, a->nota);
}
int main(void) {
Aluno ana = {"Ana", 9.5};
struct Aluno bia = {"Bia", 8.0};
mostrar(&ana);
mostrar(&bia);
printf("Uma ficha ocupa %zu bytes.\n", sizeof(Aluno));
return 0;
}
- typedef struct Aluno { … } Aluno;
- Duas coisas numa frase só: define a struct
struct Aluno(o "tipo" dotypedefé a struct inteira, com as chaves) e dá a ela o apelidoAluno(a palavra entre o}e o;). - struct Aluno / Aluno
- Repare que o nome aparece duas vezes, igual. Não há conflito: o C guarda os nomes de struct (as "etiquetas", tags, que vêm depois da palavra
struct) numa lista separada dos outros nomes.struct AlunoeAlunopodem conviver, e aqui são o mesmo tipo. - const Aluno *a
- Um ponteiro para uma ficha que a função não vai mudar (aula Structs e Ponteiros). Sem o apelido, seria
const struct Aluno *a. - struct Aluno bia
- O nome completo continua valendo:
anaebiasão do mesmo tipo, e as duas vão para o mesmomostrar.
$ gcc -std=c23 -Wall -Wextra ficha.c -o ficha $ ./ficha Ana: 9.5 Bia: 8.0 Uma ficha ocupa 40 bytes.
(Os 40 bytes são os 30 do nome, 2 de enchimento e os 8 da nota; veja sizeof.)
As três formas
Você vai encontrar três jeitos de escrever a mesma coisa:
| Forma | Código | O que dá para escrever depois |
|---|---|---|
| a) struct e typedef separados | struct Aluno { … };typedef struct Aluno Aluno; | Aluno e struct Aluno |
| b) Tudo junto, com etiqueta | typedef struct Aluno { … } Aluno; | Aluno e struct Aluno |
| c) Tudo junto, sem etiqueta (struct "anônima") | typedef struct { … } Aluno; | Só Aluno |
As três funcionam para quase tudo. A forma (c) é a mais curta, e muito usada (aparece em Arquivos Binários); o preço é que a struct não tem nome próprio, e struct Aluno deixa de existir. As formas (a) e (b) são necessárias quando a struct precisa falar dela mesma, como você vai ver na seção 3. Este guia usa a (b) quando precisa da etiqueta e a (c) quando não precisa.
Missão: o mapa do jogo da Ana escreve struct Ponto seis vezes. Crie o apelido Ponto (com qualquer uma das três formas) e use-o em todo lugar: na função somar e nas variáveis do main. A saída continua Herói em (3, 2).
#include <stdio.h>
struct Ponto {
int x;
int y;
};
struct Ponto somar(struct Ponto a, struct Ponto b) {
struct Ponto r = {a.x + b.x, a.y + b.y};
return r;
}
int main(void) {
struct Ponto heroi = {2, 3};
struct Ponto passo = {1, -1};
heroi = somar(heroi, passo);
printf("Herói em (%d, %d)\n", heroi.x, heroi.y);
return 0;
}
#include <stdio.h>
typedef struct Ponto {
int x;
int y;
} Ponto;
Ponto somar(Ponto a, Ponto b) {
Ponto r = {a.x + b.x, a.y + b.y};
return r;
}
int main(void) {
Ponto heroi = {2, 3};
Ponto passo = {1, -1};
heroi = somar(heroi, passo);
printf("Herói em (%d, %d)\n", heroi.x, heroi.y);
return 0;
}
O mesmo vale para enum e union: typedef enum { … } Status; e typedef union { … } Valor; (aulas Enums e Unions).
3. A struct que aponta para ela mesma
Um nó de lista ligada guarda um valor e um ponteiro para o próximo nó, que é do mesmo tipo. Com a forma (c), sem etiqueta, parece natural escrever assim:
#include <stdio.h>
typedef struct {
int valor;
No *prox;
} No;
int main(void) {
No b = {2, NULL};
No a = {1, &b};
printf("%d %d\n", a.valor, a.prox->valor);
return 0;
}
$ gcc -std=c23 -Wall -Wextra autoref.c -o autoref
autoref.c:5:5: error: unknown type name ‘No’
5 | No *prox;
| ^~
autoref.c: In function ‘main’:
autoref.c:10:16: error: initialization of ‘int *’ from incompatible pointer type ‘No *’ [-Wincompatible-pointer-types]
10 | No a = {1, &b};
| ^
autoref.c:10:16: note: (near initialization for ‘a.prox’)
autoref.c:11:38: error: request for member ‘valor’ in something not a structure or union
11 | printf("%d %d\n", a.valor, a.prox->valor);
| ^~
- error: unknown type name ‘No’
- "Nome de tipo desconhecido:
No". O compilador lê o arquivo de cima para baixo, e o apelidoNosó passa a existir no} No;do fim. Na linha 5, dentro das chaves, ele ainda não existe. É o erro que importa; os outros dois são consequência. - initialization of ‘int *’ from incompatible pointer type
- Sem saber o que é
No, o gcc tratou o campoproxcomoint *para continuar lendo, e aí&b(umNo *) não combina. Corrija o primeiro erro e este some.
O Clang, no editor, mostra só o primeiro: error: unknown type name 'No'. O conserto é usar a etiqueta, que já existe desde o struct No do começo:
#include <stdio.h>
typedef struct No {
int valor;
struct No *prox;
} No;
int main(void) {
No b = {2, NULL};
No a = {1, &b};
for (No *p = &a; p != NULL; p = p->prox) {
printf("%d\n", p->valor);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra autoref2.c -o autoref2 $ ./autoref2 1 2
Dentro das chaves, o campo usa o nome completo, struct No *prox; fora delas, o apelido No já vale. A outra saída é a forma (a) com o typedef antes da struct: typedef struct No No; numa linha e, depois, struct No { int valor; No *prox; };. Isso funciona porque um typedef pode apontar para uma struct que ainda vai ser descrita (uma declaração adiantada); assim o apelido já vale lá dentro.
Missão: a fila de pedidos da Ana não compila: rode e leia o unknown type name. Conserte dando uma etiqueta à struct (typedef struct Item { … } Item;) e usando struct Item *prox; dentro das chaves. A saída deve ser os números 1, 2 e 3, um por linha.
#include <stdio.h>
typedef struct {
int pedido;
Item *prox;
} Item;
int main(void) {
Item c = {3, NULL};
Item b = {2, &c};
Item a = {1, &b};
for (Item *p = &a; p != NULL; p = p->prox) {
printf("%d\n", p->pedido);
}
return 0;
}
#include <stdio.h>
typedef struct Item {
int pedido;
struct Item *prox;
} Item;
int main(void) {
Item c = {3, NULL};
Item b = {2, &c};
Item a = {1, &b};
for (Item *p = &a; p != NULL; p = p->prox) {
printf("%d\n", p->pedido);
}
return 0;
}
4. Não esconda o ponteiro
Dá para fazer typedef de um ponteiro: typedef char *Texto;. Parece prático, mas confunde, e o caso do const mostra por quê. A Ana quis prometer que mostrar não muda o texto:
#include <stdio.h>
typedef char *Texto;
void mostrar(const Texto t) {
t[0] = 'A';
printf("%s\n", t);
}
int main(void) {
char nome[] = "ana";
mostrar(nome);
return 0;
}
$ gcc -std=c23 -Wall -Wextra texto.c -o texto « nenhum aviso $ ./texto Ana
A função mudou o texto, e o compilador aceitou. O motivo: const Texto não é "const + char *" colados como palavras. O const vale para o tipo inteiro do apelido, que é o ponteiro: const Texto t quer dizer char *const t, "o ponteiro t não muda" (não pode apontar para outro lugar), e as letras continuam livres. A promessa que a Ana queria era const char *t, "as letras não mudam" (aula const e Ponteiros). Sem o apelido, o compilador barra a escrita:
$ gcc -std=c23 -Wall -Wextra texto2.c -o texto2 « o mesmo programa, com const char *t
texto2.c: In function ‘mostrar’:
texto2.c:4:10: error: assignment of read-only location ‘*t’
4 | t[0] = 'A';
| ^
"Atribuição a um lugar só de leitura, *t". No editor, o Clang diz error: read-only variable is not assignable. Moral: deixe o * à vista. Quem lê char *t sabe na hora que é um ponteiro, que pode ser NULL e que talvez precise de free; quem lê Texto t não sabe. A exceção aceita é o ponteiro para função, cujo tipo é tão difícil de ler que o apelido ajuda muito: typedef int (*Operacao)(int, int); (aula Ponteiros para Funções).
Apelido para um array
Também dá, e às vezes é útil para tamanhos fixos que se repetem:
#include <stdio.h>
#include <string.h>
typedef char Nome[16];
int main(void) {
Nome cliente = "Ana";
Nome outro;
strcpy(outro, "Bia");
printf("%s e %s, %zu bytes cada\n", cliente, outro, sizeof(Nome));
return 0;
}
$ gcc -std=c23 -Wall -Wextra nome.c -o nome $ ./nome Ana e Bia, 16 bytes cada
typedef char Nome[16]; segue a mesma receita: a declaração char Nome[16]; com typedef na frente. Nome cliente é um char cliente[16]. Cuidado com o mesmo problema de antes: um Nome passado para uma função vira um char *, como qualquer array (aula Ponteiros e Arrays), e o sizeof lá dentro dá o tamanho de um ponteiro (8 no gcc), não 16.
5. typedef × #define
Um #define (aula Macros) também parece criar um nome para um tipo. Mas ele só troca texto antes da compilação, e com ponteiros isso dá errado:
#include <stdio.h>
#define TEXTO char *
int main(void) {
TEXTO primeiro = "Ana", segundo = "Bia";
printf("%s e %s\n", primeiro, segundo);
return 0;
}
$ gcc -std=c23 -Wall -Wextra define.c -o define
define.c: In function ‘main’:
define.c:6:39: error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
6 | TEXTO primeiro = "Ana", segundo = "Bia";
| ^~~~~
define.c:7:19: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
7 | printf("%s e %s\n", primeiro, segundo);
| ~^ ~~~~~~~
| | |
| char * int
| %d
O pré-processador trocou TEXTO por char *, e a linha virou char * primeiro = "Ana", segundo = "Bia";. Numa declaração com vírgula, o * vale só para o primeiro nome: segundo é um char, uma letra só, e não cabe um texto nele ("inicializar um char com um char * transforma ponteiro em inteiro"). No editor, o Clang diz error: incompatible pointer to integer conversion initializing 'char' with an expression of type 'char[4]' [-Wint-conversion]. Com typedef char *Texto;, os dois seriam ponteiros, porque o typedef é entendido pelo compilador como um tipo de verdade, e não como texto colado. Para tipos, use sempre typedef.
6. Os typedef da biblioteca e o _t
Lembra do size_t, do FILE, do int32_t? São todos apelidos, criados nos cabeçalhos que você inclui. Dá para ver no Linux da Ana com o comando grep, que procura um texto dentro de arquivos:
$ grep -n 'typedef.*size_t;' /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h 229:typedef __SIZE_TYPE__ size_t; 231:typedef long ssize_t; $ grep -n 'typedef' /usr/include/x86_64-linux-gnu/bits/types/FILE.h 7:typedef struct _IO_FILE FILE; $ grep -n 'typedef.* int32_t;' /usr/include/x86_64-linux-gnu/bits/stdint-intn.h 26:typedef __int32_t int32_t; $ grep -n '__int32_t;' /usr/include/x86_64-linux-gnu/bits/types.h 41:typedef signed int __int32_t;
- typedef __SIZE_TYPE__ size_t;
__SIZE_TYPE__é um nome que o próprio gcc define com o tipo certo para a máquina:unsigned longno Linux de 64 bits. É por isso que osize_ttem 8 bytes no gcc e 4 no editor do guia: o apelido é o mesmo, o tipo por trás muda. O código que usasize_tfunciona nos dois sem mudar nada. Essa é a maior utilidade dotypedef: esconder o que muda de máquina para máquina.- typedef struct _IO_FILE FILE;
- O
FILEdofopen(aula Arquivos) é uma struct da glibc com um apelido, na forma (a). Você só usaFILE *e nunca mexe nos campos lá dentro. - int32_t → __int32_t → signed int
- Um apelido de um apelido: no fim, um
int32_té umintcomum (aula Inteiros de Tamanho Fixo).
_t
O _t de size_t, time_t e int32_t quer dizer type, "tipo". É a convenção da biblioteca padrão. A norma POSIX (a dos sistemas como o Linux) reserva para ela mesma todos os nomes terminados em _t, para poder criar tipos novos no futuro sem bater nos seus. Por isso, nos seus programas, prefira nomes como Aluno, Dinheiro e Ponto, com letra maiúscula, que é o estilo deste guia. Você vai ver muito código com aluno_t; funciona, só não é o recomendado.
typeof C23
O typeof(expressão) dá o tipo de uma variável ou expressão, sem você precisar escrevê-lo: typeof(preco) troco = 50 - preco; cria troco com o mesmo tipo de preco (num programa com Dinheiro preco = 19.90;, ele mostrou Troco: R$ 30.10 (8 bytes) no gcc e no editor). Ele não substitui o typedef, que dá um nome ao tipo; é útil dentro de macros. Veja Novidades do C99 ao C23.
Qual usar
| Situação | Recomendação |
|---|---|
| Uma struct, enum ou union usada em vários lugares | typedef, forma (c) typedef struct { … } Nome; |
| Uma struct que aponta para ela mesma (listas, árvores) | Forma (b) typedef struct Nome { … struct Nome *prox; } Nome; ou (a) com o typedef antes |
| Um número com um significado (dinheiro, medida, identificador) | typedef, sabendo que ele documenta mas não protege |
| Um tipo que muda de máquina para máquina | Os da biblioteca (size_t, int32_t) ou um typedef seu num cabeçalho |
| Ponteiro para função | typedef: fica muito mais legível |
Ponteiro comum (char *, Aluno *) | Sem typedef: deixe o * à vista |
Nome para um tipo com #define | Não: use typedef |
Alguns projetos grandes, como o núcleo do Linux, proíbem typedef para structs: preferem escrever struct aluno sempre, para que fique claro, em cada linha, que aquilo é uma struct. Outros, como muitas bibliotecas de jogos e de interface gráfica, usam typedef em tudo. As duas escolhas são boas; o importante é seguir a do projeto em que você está.
Quando dá errado
error: unknown type name ‘Aluno’; use ‘struct’ keyword to refer to the type
$ gcc -std=c23 -Wall -Wextra semtypedef.c -o semtypedef
semtypedef.c: In function ‘main’:
semtypedef.c:9:5: error: unknown type name ‘Aluno’; use ‘struct’ keyword to refer to the type
9 | Aluno ana = {"Ana", 9.5};
| ^~~~~
| struct
«… mais erros, todos consequência deste …»
O que significa: o programa tem struct Aluno { … }; mas nenhum typedef, e usa Aluno sozinho. O gcc até sugere: "use a palavra struct". No editor, o Clang diz error: must use 'struct' tag to refer to type 'Aluno'.
Como consertar: escreva struct Aluno ana, ou crie o apelido: typedef struct Aluno Aluno; depois da struct.
error: unknown type name ‘No’ dentro da própria struct
O que significa: a struct usa o apelido antes de ele existir (seção 3).
Como consertar: dê uma etiqueta à struct e use struct No *prox; dentro das chaves, ou ponha typedef struct No No; antes da struct.
error: storage size of ‘ana’ isn’t known com struct Aluno ana
$ gcc -std=c23 -Wall -Wextra incompleto.c -o incompleto
incompleto.c: In function ‘main’:
incompleto.c:9:12: error: variable ‘ana’ has initializer but incomplete type
9 | struct Aluno ana = {"Ana", 9.5};
| ^~~~~
«… avisos de "excess elements in struct initializer" …»
incompleto.c:9:18: error: storage size of ‘ana’ isn’t known
9 | struct Aluno ana = {"Ana", 9.5};
| ^~~
O que significa: a struct foi criada na forma (c), typedef struct { … } Aluno;, sem etiqueta. Então struct Aluno não existe: o compilador acha que é outra struct, ainda não descrita ("tipo incompleto"), e não sabe quantos bytes ela tem ("o tamanho de ana não é conhecido"). No editor: error: variable has incomplete type 'struct Aluno'.
Como consertar: escreva só Aluno ana, ou dê a etiqueta à struct (forma b).
error: conflicting types for ‘Idade’; have ‘long int’
$ gcc -std=c23 -Wall -Wextra conflito.c -o conflito
conflito.c:5:14: error: conflicting types for ‘Idade’; have ‘long int’
5 | typedef long Idade;
| ^~~~~
conflito.c:4:13: note: previous declaration of ‘Idade’ with type ‘Idade’ {aka ‘int’}
4 | typedef int Idade;
| ^~~~~
O que significa: o mesmo apelido foi definido duas vezes com tipos diferentes (as linhas 4 e 5). Repetir o mesmo typedef (as linhas 3 e 4 do programa, typedef int Idade; duas vezes) é permitido desde o C11; com tipos diferentes, não. O {aka ‘int’} ("também conhecido como") é como o gcc mostra o tipo por trás de um apelido. No editor: error: typedef redefinition with different types ('long' vs 'int').
Como consertar: deixe um typedef só, num cabeçalho incluído por todos os arquivos que usam o apelido (aula Arquivos de Cabeçalho).
makes integer from pointer without a cast num tipo criado com #define
O que significa: o #define de um tipo com * só faz do primeiro nome de uma declaração com vírgula um ponteiro (seção 5).
Como consertar: troque o #define por typedef, ou declare cada variável numa linha.
Referência rápida
| Código | O que cria |
|---|---|
typedef double Dinheiro; | Dinheiro = double |
typedef struct { … } Aluno; | Aluno = uma struct sem etiqueta |
typedef struct No { … struct No *prox; } No; | No = struct No, que aponta para ela mesma |
typedef struct No No; | O apelido antes da descrição da struct (declaração adiantada) |
typedef enum { … } Status; / typedef union { … } Valor; | Apelidos para enum e union |
typedef char Nome[16]; | Nome x; = char x[16]; |
typedef int (*Operacao)(int, int); | Apelido para ponteiro de função |
typedef char *Texto; | Funciona, mas evite: const Texto é char *const |
size_t, FILE, int32_t, time_t | Apelidos da biblioteca; o _t é reservado pelo POSIX |
Exercícios
1. Um apelido simples
Complete para que Nota seja um apelido de double:
2. O nome que fica
Depois de typedef struct { int x; int y; } Ponto;, complete a declaração da variável p:
3. A etiqueta
Complete o campo para a struct apontar para ela mesma:
4. Com typedef int Metros; e typedef int Segundos;, o que acontece se uma função que recebe Metros for chamada com uma variável Segundos?
5. Com typedef char *Texto;, o que é const Texto t?
6. Por que size_t tem 8 bytes no gcc do Linux e 4 no editor do guia?
Missão final: o estoque da lojinha
Missão: o programa usa os tipos Dinheiro e Produto, mas ninguém os criou, e ele não compila. Escreva os dois typedef no lugar do comentário: Dinheiro como apelido de double, e Produto como uma struct com os campos nome (char[20]), quantidade (int) e preco (Dinheiro), nessa ordem. A última linha da saída deve ser Valor do estoque: R$ 364.50.
#include <stdio.h>
/* crie aqui os tipos Dinheiro e Produto */
Dinheiro valor_estoque(const Produto *itens, int n) {
Dinheiro total = 0;
for (int i = 0; i < n; i++) {
total += itens[i].quantidade * itens[i].preco;
}
return total;
}
int main(void) {
Produto loja[] = {
{"Caderno", 10, 12.50},
{"Caneta", 30, 1.99},
{"Mochila", 2, 89.90},
};
int n = sizeof loja / sizeof loja[0];
for (int i = 0; i < n; i++) {
printf("%-8s %3d x R$ %6.2f\n", loja[i].nome, loja[i].quantidade, loja[i].preco);
}
printf("Valor do estoque: R$ %.2f\n", valor_estoque(loja, n));
return 0;
}
#include <stdio.h>
typedef double Dinheiro;
typedef struct {
char nome[20];
int quantidade;
Dinheiro preco;
} Produto;
Dinheiro valor_estoque(const Produto *itens, int n) {
Dinheiro total = 0;
for (int i = 0; i < n; i++) {
total += itens[i].quantidade * itens[i].preco;
}
return total;
}
int main(void) {
Produto loja[] = {
{"Caderno", 10, 12.50},
{"Caneta", 30, 1.99},
{"Mochila", 2, 89.90},
};
int n = sizeof loja / sizeof loja[0];
for (int i = 0; i < n; i++) {
printf("%-8s %3d x R$ %6.2f\n", loja[i].nome, loja[i].quantidade, loja[i].preco);
}
printf("Valor do estoque: R$ %.2f\n", valor_estoque(loja, n));
return 0;
}
Repare que o typedef double Dinheiro; tem de vir antes do Produto, que o usa: o compilador lê de cima para baixo. Depois de passar na missão, experimente trocar o double por float só na linha do typedef: o resto do programa se ajusta sozinho.
Resumo
typedef tipo Apelido;dá um nome novo a um tipo que já existe. A receita: escreva a declaração como se fosse uma variável e ponhatypedefna frente.- O apelido é o mesmo tipo: mistura sem aviso. Ele documenta a intenção, mas não protege.
- Com struct:
typedef struct { … } Aluno;(sem etiqueta) outypedef struct Aluno { … } Aluno;(com etiqueta). Uma struct que aponta para ela mesma precisa da etiqueta:struct No *prox;, senão dáunknown type name. - Não esconda ponteiros num
typedef(const Textoéchar *const); a exceção é o ponteiro para função. - Para tipos, use
typedef, não#define: o#definesó troca texto, eTEXTO a, b;faz debumchar. size_t,FILEeint32_tsão typedef da biblioteca; é por isso que osize_tmuda de tamanho entre o gcc (8 bytes) e o editor (4). O sufixo_té reservado pelo POSIX.