Para quem já passou do básico: const, enum, typedef, errno, variádica, compilação condicional.
const é como você diz ao sistema de tipos "prometo que não vou modificar isto". Deixa a intenção clara e pega erros em tempo de compilação.int sum_array(const int *a, int n) { int s = 0; for (int i = 0; i < n; i++) s += a[i]; // a[i] = 0; // erro de compilação — somente leitura return s; }
const int *p → *p é somente leitura, p pode mudarint * const p → p é fixo, *p é gravávelconst int * const p → nenhum dos dois* — o que estiver à esquerda descreve o alvo; o que estiver à direita descreve o ponteiro.
const int MAX = 100; // mais seguro em tipo do que #define const double PI = 3.14159265358979;
const em APIs de biblioteca — é um contrato com quem chama sua função.switch e elimina números mágicos.// Ruim: número mágico int state = 2; if (state == 3) { /* o que é 3? */ } // Bom: enum enum Color { RED, GREEN, BLUE }; // 0, 1, 2 enum Color c = GREEN; if (c == RED) { /* o significado fica claro */ }
enum HttpStatus { HTTP_OK = 200, HTTP_NOT_FOUND = 404, HTTP_SERVER_ERROR = 500 };
enum State { STATE_IDLE, STATE_RUN, STATE_STOP }; void handle(enum State s) { switch (s) { case STATE_IDLE: printf("idle\n"); break; case STATE_RUN: printf("run\n"); break; case STATE_STOP: printf("stop\n"); break; } }
-Wswitch-enum avisa quando um switch não cobre todos os valores do enum.// typedef de struct typedef struct { int x; int y; } Point; Point p = {3, 4}; // ponteiro de função typedef int (*CmpFn)(const void *, const void *); CmpFn cmp; // arrays também typedef char Buffer[256]; Buffer name; // igual a char name[256]
| typedef | tipo subjacente | uso |
|---|---|---|
size_t | unsigned long | tamanhos & índices |
ssize_t | long | tamanhos com sinal |
int32_t / uint64_t | int / unsigned long | largura explícita |
time_t | long | tempo UNIX |
FILE | struct ... | descritor de arquivo |
typedef struct S *SPtr;) — quem lê não consegue mais dizer quais variáveis são ponteiros.errno quando falham. perror ou strerror transforma esse código numa mensagem legível por humanos.#include <stdio.h> #include <string.h> #include <errno.h> int main(void) { FILE *fp = fopen("arquivo_inexistente.txt", "r"); if (fp == NULL) { perror("fopen"); fprintf(stderr, "erro %d: %s\n", errno, strerror(errno)); return 1; } fclose(fp); return 0; }
| Constante | Significado |
|---|---|
ENOENT | Arquivo ou diretório não encontrado |
EACCES | Permissão negada |
ENOMEM | Memória esgotada |
EINVAL | Argumento inválido |
EAGAIN | Recurso temporariamente indisponível |
EINTR | Interrompido por um sinal |
errno depois que uma função reportar falha.strtol, defina errno = 0; antes da chamada para conseguir distinguir sucesso de overflow.printf que aceitam um número variável de argumentos. Usa <stdarg.h>.#include <stdio.h> #include <stdarg.h> int sum(int count, ...) { va_list ap; va_start(ap, count); int total = 0; for (int i = 0; i < count; i++) { total += va_arg(ap, int); } va_end(ap); return total; } int main(void) { printf("%d\n", sum(3, 10, 20, 30)); // 60 printf("%d\n", sum(5, 1, 2, 3, 4, 5)); // 15 }
va_arg; incompatibilidade é comportamento indefinido.char e short são promovidos para int — use va_arg(ap, int), não va_arg(ap, char).void log_info(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "[INFO] "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } log_info("usuário %s entrou em %d", name, ts);
#ifdef DEBUG printf("x = %d\n", x); #endif // compilado com 'gcc -DDEBUG' → printf habilitado // caso contrário, removido
#define VERSION 3 #if VERSION >= 2 // recursos da v2+ #else // fallback da v1 #endif
#if defined(_WIN32) #include <windows.h> Sleep(1000); #elif defined(__APPLE__) || defined(__linux__) #include <unistd.h> sleep(1); #else #error "plataforma não suportada" #endif
| Macro | Significado |
|---|---|
__FILE__ | arquivo atual |
__LINE__ | linha atual |
__func__ | nome da função (C99+) |
__DATE__ / __TIME__ | data/hora do build |
__STDC_VERSION__ | versão do padrão C |
// Macro prática de depuração #define LOG(...) \ fprintf(stderr, "[%s:%d %s] ", __FILE__, __LINE__, __func__), \ fprintf(stderr, __VA_ARGS__), \ fprintf(stderr, "\n") LOG("x = %d", x); // saída: [main.c:42 main] x = 10
#ifndef FOO_H / #define / #endif. Amplamente suportado, mas não padronizado.Teste seu entendimento desta aula!
const int *p e int * const p?O lado do * em que o const está determina se ele se aplica ao valor apontado ou ao próprio ponteiro.
Sem valores explícitos, um enum começa em 0 e incrementa de 1 em 1. Você pode atribuir um valor no meio para mudar a sequência a partir daquele ponto.
va_list, va_start, va_arg e va_end estão todos definidos em <stdarg.h>. É o mesmo header do qual printf depende.