C Novidades do C99 ao C23
O C de hoje não é o C de 1989. A cada dez anos, mais ou menos, a linguagem ganha uma versão nova, com recursos que deixam o código mais curto e mais seguro. Este guia ensina o C23, a versão mais recente, mas você vai ler muito código escrito em C89, C99 e C11. Esta aula é o mapa: o que cada versão trouxe, como saber qual versão o compilador está usando, e o C23 em detalhe, com exemplos que compilam no gcc 15.
- A linha do tempo: K&R, C89, C99, C11, C17, C23 e o próximo, o C2y.
- Como pedir uma versão ao compilador (
-std=) e como o programa descobre a sua (__STDC_VERSION__). - Os destaques do C99 e do C11, que você vai encontrar em todo código "moderno".
- O C23 por partes:
bool,nullptr,constexpr,typeof,auto,0b1010,1'000,#embed,#elifdef, atributos,static_assertsem mensagem,unreachable(),memset_explicit,strdupe%b. - O que mudou de um jeito que quebra código antigo (
int f();). - O que já foi aprovado para o C2y e o que ainda é só proposta.
Os programas desta aula foram compilados com o gcc 15.2 na máquina da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia, gcc -std=c23 -Wall -Wextra arquivo.c -o programa, e conferidos também no editor do guia (Clang 22). Quando os dois discordam, a aula diz. A história completa das versões está em Versões do C.
A ideia: as edições de um dicionário
Um dicionário ganha edições novas de tempos em tempos. Cada edição acrescenta palavras ("selfie", "aplicativo"), às vezes corrige definições e, raramente, tira alguma coisa. Um texto escrito com a edição de 1990 continua legível com a de 2024; o contrário nem sempre: quem só tem a edição velha não acha "aplicativo".
Com o C é igual. A "edição" oficial se chama padrão (standard), escrita por um comitê internacional (ISO). Programas antigos quase sempre compilam com o compilador novo. Mas um programa que usa nullptr (C23) não compila num compilador que só conhece o C17. E o compilador precisa saber qual edição você está seguindo: é para isso que serve a opção -std=.
1. A linha do tempo
| Versão | Ano | Principais novidades |
|---|---|---|
| K&R C | 1978 | O C do livro de Kernighan e Ritchie. Não era um padrão oficial. |
| C89 / C90 (ANSI C) | 1989/1990 | O primeiro padrão. Protótipos de função, void, const, a biblioteca padrão (stdio.h, stdlib.h, string.h…). Comentários só com /* */ e variáveis só no começo do bloco. |
| C99 | 1999 | Comentários //, for (int i = 0; …), bool via stdbool.h, stdint.h (int32_t), long long, snprintf, inicializadores com nome (.x = 1), VLAs, inline, tgmath.h. |
| C11 | 2011 | _Generic, _Static_assert, _Noreturn, _Alignas, threads (threads.h) e atômicos opcionais, structs e unions anônimas, strings u8"…". O gets foi removido. |
| C17 (ou C18) | 2018 | Só correções do C11. Nenhum recurso novo. |
| C23 | 2024 | bool/true/false como palavras-chave, nullptr, constexpr, typeof, auto, atributos [[…]], 0b1010, 1'000, #embed, #elifdef, static_assert sem mensagem, unreachable(), strdup, %b… |
| C2y | em preparo | O próximo. O "y" é provisório: ninguém sabe o ano. Veja a seção 6. |
O nome vem do ano em que o texto ficou pronto: o C23 foi aprovado em 2023 e publicado pela ISO em 2024 (por isso o valor do __STDC_VERSION__, logo abaixo, é 202311: novembro de 2023).
2. Qual versão o compilador está usando?
O programa pode perguntar. A macro __STDC_VERSION__, que o próprio compilador define, diz o ano e o mês da versão:
#include <stdio.h>
int main(void) {
printf("__STDC_VERSION__ = %ld\n", __STDC_VERSION__);
return 0;
}
$ gcc versao.c -o versao && ./versao « sem -std: o padrão do gcc 15 __STDC_VERSION__ = 202311 $ gcc -std=c99 versao.c -o versao && ./versao __STDC_VERSION__ = 199901 $ gcc -std=c11 versao.c -o versao && ./versao __STDC_VERSION__ = 201112 $ gcc -std=c17 versao.c -o versao && ./versao __STDC_VERSION__ = 201710 $ gcc -std=c23 versao.c -o versao && ./versao __STDC_VERSION__ = 202311
- -std=c99, -std=c11…
- "Standard": pede ao gcc que siga aquela edição. Recursos mais novos passam a dar erro.
- sem -std
- O gcc 15 usa
gnu23: o C23 mais algumas extensões do gcc. Compiladores mais velhos usavamgnu17ougnu11, e é por isso que tanta gente ainda vê erros emnullptroubool. - 199901, 201112…
- Ano e mês:
199901= janeiro de 1999. Com#if __STDC_VERSION__ >= 202311L, um programa pode usar um recurso novo só quando ele existe (aula Compilação Condicional).
Com -std=c89 nem esse programa compila: o __STDC_VERSION__ só passou a existir depois do C89. O editor do guia compila em C23, como o laboratório; outras versões só com data-flags na própria caixa (veja O Editor do Guia).
3. C99 e C11: o "C moderno" que você já usa
Muito do que este guia usa desde o primeiro dia veio do C99. Para sentir a diferença, veja este programa curtinho compilado como C89:
#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++) { // C99: variável dentro do for, comentário //
printf("%d ", i);
}
printf("\n");
return 0;
}
$ gcc -std=c89 -Wall -Wextra linhas.c -o linhas
linhas.c: In function ‘main’:
linhas.c:4:5: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode
4 | for (int i = 0; i < 3; i++) { // C99: variável dentro do for, comentário //
| ^~~
linhas.c:4:5: note: use option ‘-std=c99’, ‘-std=gnu99’, ‘-std=c11’ or ‘-std=gnu11’ to compile your code
linhas.c:4:37: error: C++ style comments are not allowed in ISO C90
4 | for (int i = 0; i < 3; i++) { // C99: variável dentro do for, comentário //
| ^
linhas.c:4:37: note: (this will be reported only once per input file)
Dois erros em uma linha: "declarações no começo do for só são permitidas no modo C99 ou C11" e "comentários no estilo C++ não são permitidos no ISO C90". Em C89, o i tinha de ser declarado no começo do main e o comentário escrito com /* */. É assim que muito código antigo é escrito, e agora você sabe por quê.
| Recurso | Versão | Aula |
|---|---|---|
// comentário, for (int i…), declarar variável no meio do bloco | C99 | Comentários, for |
bool com #include <stdbool.h> | C99 | Booleanos |
int32_t, uint8_t (stdint.h) | C99 | Inteiros de Tamanho Fixo |
snprintf | C99 | Texto ↔ Número |
struct ponto p = { .x = 1, .y = 2 }; | C99 | Structs |
inline | C99 | Funções inline |
_Generic | C11 | _Generic |
_Static_assert | C11 | static_assert |
_Noreturn | C11 | Atributos |
gets removido (use fgets) | C11 | Ler uma Linha |
threads.h (opcional) | C11 | Threads |
4. O C23 em detalhe
O C23 foi a maior atualização desde o C99. Boa parte dela traz para o C ideias que já existiam no C++. Este programa usa várias de uma vez:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
bool aberto = true; // bool, true e false sem include
int *p = nullptr; // nullptr
constexpr int MAX = 1'000'000; // constexpr e separador '
int mascara = 0b1010; // binário
auto total = 2.5 * 4; // auto deduz double
typeof(total) metade = total / 2; // typeof
printf("%d %d %d %d\n", aberto, p == nullptr, MAX, mascara);
printf("%.1f %.1f\n", total, metade);
printf("%b\n", 10u); // %b no printf
char *copia = strdup("Ana"); // strdup agora é padrão
printf("%s\n", copia);
free(copia);
printf("%ld\n", __STDC_VERSION__);
return 0;
}
$ gcc -std=c23 -Wall -Wextra c23.c -o c23 $ ./c23 1 1 1000000 10 10.0 5.0 1010 Ana 202311
Agora, uma por uma.
bool, true e false sem include
Até o C17, era preciso #include <stdbool.h>; sem ele, bool dava unknown type name ‘bool’. No C23 são palavras-chave. O stdbool.h continua existindo (e não faz mal), só não é mais necessário. Aula: Booleanos.
nullptr
O "ponteiro nulo" com tipo próprio, no lugar do NULL, que é só uma macro para 0 ou ((void*)0). Com nullptr, o compilador sempre sabe que é um ponteiro, inclusive em funções variádicas e no _Generic. Aula: Ponteiro Nulo.
constexpr
Uma constante que o compilador conhece na compilação, e que pode ser usada onde o C exige uma constante (tamanho de array global, case, static_assert). Diferente de const, que só proíbe mudar. No C23, constexpr vale só para variáveis; funções constexpr (que existem no C++) não chegaram ao C. Aula: Constantes.
0b1010 e 1'000'000
Números em binário com o prefixo 0b (antes, só uma extensão do gcc) e o apóstrofo como separador de dígitos, para ler números grandes: 1'000'000 é um milhão. O apóstrofo pode ir em qualquer posição e não muda o valor. Aula: Inteiros.
typeof, typeof_unqual e auto
typeof(x)é "o tipo dex". Era uma extensão do gcc havia décadas; agora é padrão. Muito usado em macros.typeof_unqual(x)é o mesmo tipo, mas semconstevolatile. Comconst int a = 5;,typeof(a) bcria umconst int, que não pode mudar;typeof_unqual(a) ccria umintcomum.auto total = 2.5 * 4;deixa o compilador deduzir o tipo pelo valor (double). No C antigo,autoexistia mas não servia para nada ("variável local", que já é o normal). No C23 ele funciona só para variáveis com valor inicial; não vale para parâmetros nem para o retorno de funções.
$ cat typeofu.c
#include <stdio.h>
int main(void) {
const int a = 5;
typeof(a) b = 6;
typeof_unqual(a) c = 7;
c = c + 1;
printf("%d %d %d\n", a, b, c);
return 0;
}
$ gcc -std=c23 -Wall -Wextra typeofu.c -o typeofu && ./typeofu
5 6 8
Use auto com moderação: int idade = 29; diz mais a quem lê do que auto idade = 29;.
%b no printf
Mostra um número em binário: printf("%b", 10u) escreve 1010. Funciona com a biblioteca do laboratório (glibc).
%b não funciona
A biblioteca do editor (wasi-libc, baseada na musl) ainda não conhece o %b. Quando o printf encontra um formato que não conhece, ele desiste da linha inteira: printf("[%b]\n", 10u) não mostra nem o [, e o Clang não avisa nada. No programa c23.c acima, a linha 1010 simplesmente some no editor. Para mostrar binário em qualquer biblioteca, faça um laço com >> e & (aula Operadores de Bits).
strdup e strndup
strdup("Ana") ("string duplicate") reserva memória com malloc e copia o texto para lá; depois, free. Existiam havia muito tempo no POSIX (Linux, macOS); o C23 os trouxe para o padrão. No editor, strdup funciona, mas strndup ainda não existe (use of undeclared identifier 'strndup'). Aula: Strings Dinâmicas.
Experimente: rode o programa do C23 no editor. Repare que a linha do %b não aparece (explicado acima). Depois troque auto total = 2.5 * 4; por auto total = 2 * 4; e veja o que muda na segunda linha: o tipo deduzido agora é int, e o %.1f passa a receber o tipo errado (leia o aviso).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
bool aberto = true;
int *p = nullptr;
constexpr int MAX = 1'000'000;
int mascara = 0b1010;
auto total = 2.5 * 4;
typeof(total) metade = total / 2;
printf("%d %d %d %d\n", aberto, p == nullptr, MAX, mascara);
printf("%.1f %.1f\n", total, metade);
printf("%b\n", 10u);
char *copia = strdup("Ana");
printf("%s\n", copia);
free(copia);
printf("%ld\n", __STDC_VERSION__);
return 0;
}
#embed: um arquivo dentro do programa
Uma diretiva nova do pré-processador (aula Pré-processador): ela coloca os bytes de um arquivo dentro de um array, na compilação. Antes, isso exigia ferramentas externas (como o xxd -i). Serve para embutir imagens, sons, textos de ajuda:
#include <stdio.h>
static const char mensagem[] = {
#embed "aviso.txt"
, '\0'
};
int main(void) {
printf("%s", mensagem);
printf("(%zu bytes)\n", sizeof mensagem - 1);
return 0;
}
$ cat aviso.txt Loja fechada no domingo. $ gcc -std=c23 -Wall -Wextra emb.c -o emb $ ./emb Loja fechada no domingo. (25 bytes) $ rm aviso.txt; ./emb « o arquivo já está dentro do programa Loja fechada no domingo. (25 bytes)
- #embed "aviso.txt"
- Vira a lista dos bytes do arquivo, separados por vírgula:
76, 111, 106, 97, …("L", "o", "j", "a"…). - , '\0'
- O arquivo não termina com o
'\0'que toda string precisa (aula Strings). A vírgula e o'\0'o acrescentam. - (25 bytes)
- 24 letras e espaços mais o
\ndo fim da linha.
Repare na diferença para ler o arquivo com fopen (aula Ler Arquivos): com #embed, o arquivo é lido pelo compilador, uma vez; o programa pronto já carrega o conteúdo e não precisa do arquivo para rodar.
#elifdef, #elifndef e #warning
Atalhos do pré-processador: #elifdef X é o mesmo que #elif defined(X), e #elifndef X, o mesmo que #elif !defined(X). O #warning "texto", que já existia no gcc, virou padrão: ele mostra um aviso na compilação.
#include <stdio.h>
#define LINUX
int main(void) {
#ifdef WINDOWS
printf("Windows\n");
#elifdef LINUX
printf("Linux\n");
#else
printf("outro\n");
#endif
return 0;
}
$ gcc -std=c23 -Wall -Wextra elifdef.c -o elifdef && ./elifdef Linux
Atributos [[…]] e static_assert sem mensagem
[[nodiscard]], [[maybe_unused]], [[deprecated]], [[fallthrough]] e [[noreturn]] contam ao compilador o que ele não adivinha (aula Atributos). E o static_assert virou palavra-chave, com a mensagem opcional: static_assert(sizeof(int) == 4); (aula static_assert).
unreachable()
De stddef.h. Diz ao compilador "o programa nunca chega aqui". Ele usa isso para otimizar e para não avisar sobre um caminho que você sabe que não existe:
#include <stdio.h>
#include <stddef.h>
const char *nome_dia(int d) {
switch (d) {
case 0: return "domingo";
case 6: return "sábado";
default:
if (d > 0 && d < 6) return "dia útil";
unreachable();
}
}
int main(void) {
printf("%s\n", nome_dia(6));
return 0;
}
$ gcc -std=c23 -Wall -Wextra unreach.c -o unreach && ./unreach sábado
Sem o unreachable(), o gcc avisaria que a função pode chegar ao fim sem return. Cuidado: se o programa chegar ali (alguém chamou nome_dia(9)), é comportamento indefinido, não um erro com mensagem (aula Comportamento Indefinido). Use só quando tiver certeza; para conferir, prefira assert.
memset_explicit
Apagar uma senha da memória com memset(senha, 0, …) parece fácil, mas o otimizador pode remover esse memset se a variável não for mais lida depois ("para que zerar algo que ninguém vai ler?"). A senha fica na memória. O memset_explicit, de string.h, nunca é removido:
#include <stdio.h>
#include <string.h>
int main(void) {
char senha[16] = "segredo123";
printf("Usando a senha...\n");
memset_explicit(senha, 0, sizeof senha);
printf("Apagada: [%s]\n", senha);
return 0;
}
$ gcc -std=c23 -Wall -Wextra memset.c -o memset && ./memset Usando a senha... Apagada: []
No editor do guia ele ainda não existe: o Clang diz use of undeclared identifier 'memset_explicit'. A aula Segurança volta ao assunto.
Outras novidades do C23
| Recurso | Exemplo | gcc 15 | Editor |
|---|---|---|---|
| Zerar com chaves vazias | int v[5] = {}; | Sim | Sim |
enum com tipo escolhido | enum cor : unsigned char { … }; (1 byte) | Sim | Sim |
| Conta que avisa se estourar | ckd_add(&r, a, b) de stdckdint.h devolve true se não coube | Sim | Sim |
| Funções de bits | stdc_count_ones(255u) de stdbit.h (conta os bits 1: 8) | Sim | Não (falta o stdbit.h) |
| Inteiros de qualquer largura | _BitInt(12) x = 100; | Sim | Sim |
| Parâmetro sem nome na definição | void botao(int) { … } | Sim | Sim |
alignas, thread_local sem include | thread_local static int n; | Sim | Sim |
Missão: modernize este programa escrito no estilo C99. Troque o #define MAX 1000000 por constexpr int MAX = 1'000'000; dentro do main (com o separador), troque os dois NULL por nullptr e apague o #include <stdbool.h>, que não é mais necessário. A saída tem de continuar 1000000 0 1.
#include <stdio.h>
#include <stdbool.h>
#define MAX 1000000
int main(void) {
bool achou = false;
int *p = NULL;
printf("%d %d %d\n", MAX, achou, p == NULL);
return 0;
}
#include <stdio.h>
int main(void) {
constexpr int MAX = 1'000'000;
bool achou = false;
int *p = nullptr;
printf("%d %d %d\n", MAX, achou, p == nullptr);
return 0;
}
5. O que o C23 quebrou: int f();
Quase todo código antigo compila igual no C23. A exceção mais importante: uma declaração com parênteses vazios. Até o C17, int soma(); queria dizer "uma função que recebe não sei quantos parâmetros" (um resto do K&R C). No C23, quer dizer "recebe nenhum", igual a int soma(void);:
#include <stdio.h>
int soma();
int main(void) {
printf("%d\n", soma(2, 3));
return 0;
}
int soma(int a, int b) { return a + b; }
$ gcc -std=c23 -Wall -Wextra velho.c -o velho
velho.c: In function ‘main’:
velho.c:6:20: error: too many arguments to function ‘soma’; expected 0, have 2
6 | printf("%d\n", soma(2, 3));
| ^~~~ ~
velho.c:3:5: note: declared here
3 | int soma();
| ^~~~
velho.c: At top level:
velho.c:10:5: error: conflicting types for ‘soma’; have ‘int(int, int)’
10 | int soma(int a, int b) { return a + b; }
| ^~~~
velho.c:3:5: note: previous declaration of ‘soma’ with type ‘int(void)’
3 | int soma();
| ^~~~
"Argumentos demais para a função soma; esperava 0, recebeu 2" e "tipos em conflito para soma": a declaração da linha 3 agora diz int(void). O conserto é escrever o protótipo completo, int soma(int a, int b); (aula Protótipos). Também saíram do C23 as definições de função no estilo K&R (com os tipos dos parâmetros depois dos parênteses), que ninguém deveria usar havia 30 anos.
6. O que vem no C2y
O comitê já trabalha na próxima versão, apelidada de C2y. Nada está publicado, e tudo pode mudar até o fim. Alguns recursos já foram aprovados para o rascunho, e o gcc 15 e o Clang 22 testam parte deles com -std=c2y:
| Recurso (rascunho do C2y) | Exemplo | gcc 15 | Clang 22 (editor) |
|---|---|---|---|
Prefixo 0o para octal | 0o17 (= 15), mais claro que o velho 017 | Sim | Sim |
_Generic com um tipo | _Generic(int, int: "int", …) | Sim | Sim |
| Laços com nome | fora: for (…) { … break fora; } | Sim | Sim |
Declaração dentro do if | if (int n = ler(); n > 0) | Sim | Não |
| Operador para contar itens de array | _Countof(notas) | Não | Sim |
E o defer? É uma proposta muito comentada: um comando que roda "na saída do bloco", útil para nunca esquecer um free ou fclose. Por enquanto ele está sendo discutido numa especificação técnica separada (um documento experimental), não no rascunho do C2y, e nem o gcc 15 nem o Clang 22 o aceitam (error: unknown type name ‘defer’). Se e quando ele vai entrar no C, ninguém sabe ainda.
O -std=c2y existe para testar. A escrita pode mudar até a publicação (o próprio _Countof já trocou de nome durante as discussões). Para programas que você vai manter, fique no -std=c23.
7. Qual versão usar
| Situação | Use |
|---|---|
| Aprender, projetos novos, gcc 14+ ou Clang 18+ | -std=c23 (é o que este guia faz) |
| Projeto que precisa compilar em compiladores mais velhos ou em microcontroladores | -std=c11 ou -std=c17, com stdbool.h, NULL e _Static_assert |
| Código muito antigo, ou o projeto exige | -std=c99 (raramente -std=c89) |
| Testar o futuro | -std=c2y, só para experimentar |
Escreva sempre o -std= no comando (ou no Makefile, aula Makefile). Assim o programa compila igual em qualquer computador, mesmo que o padrão do compilador mude na próxima versão.
Quando dá errado
error: ‘nullptr’ undeclared (first use in this function)
$ gcc -std=c17 -Wall -Wextra antigo.c -o antigo
antigo.c: In function ‘main’:
antigo.c:4:14: error: ‘nullptr’ undeclared (first use in this function)
4 | int *p = nullptr;
| ^~~~~~~
antigo.c:4:14: note: each undeclared identifier is reported only once for each function it appears in
O que significa: o código usa um recurso do C23, mas o compilador está em C17 (pelo -std= ou porque é uma versão antiga do gcc). Para ele, nullptr é só um nome desconhecido. O mesmo acontece com bool (unknown type name ‘bool’), constexpr e typeof.
Como consertar: compile com -std=c23. Se não puder, use as formas antigas: NULL, #include <stdbool.h>, #define ou enum.
error: too many arguments to function ‘soma’; expected 0, have 2
O que significa: código antigo com int soma(); compilado em C23, onde () quer dizer "nenhum parâmetro".
Como consertar: escreva o protótipo completo, int soma(int a, int b);.
use of undeclared identifier 'memset_explicit' (ou a linha do %b some)
O que significa: o compilador entende o C23, mas a biblioteca do editor (wasi-libc) ainda não tem todas as funções novas. Linguagem e biblioteca andam separadas: o mesmo acontece em outros sistemas.
Como consertar: confira no laboratório (gcc + glibc). No editor, use as alternativas: memset comum, um laço para o binário, malloc + memcpy no lugar de strndup.
Referência rápida
| Versão | __STDC_VERSION__ | -std= | Lembre por |
|---|---|---|---|
| C89/C90 | (não existe) | c89 ou c90 | Primeiro padrão, /* */ |
| C99 | 199901L | c99 | //, for (int i…), stdint.h, stdbool.h |
| C11 | 201112L | c11 | _Generic, _Static_assert, sem gets |
| C17 | 201710L | c17 | Correções |
| C23 | 202311L | c23 (padrão do gcc 15: gnu23) | bool, nullptr, constexpr, [[…]], #embed |
| C2y | (provisório) | c2y | Rascunho: 0o17, laços com nome… |
Exercícios
1. O ponteiro nulo do C23
Complete com a palavra-chave do C23 para o ponteiro nulo:
2. Pedir a versão
Complete a opção do gcc para compilar como C11:
3. Em que versão os comentários // e o for (int i = 0; …) entraram no C?
4. No C23, o que quer dizer int f();?
5. Sobre o defer, o que é verdade hoje?
6. O que o #embed "logo.png" faz?
Missão final: a promoção embutida
Missão: a caixa tem duas abas: o programa e o arquivo frase.txt. Hoje o array frase está vazio e o programa mostra (0 bytes). Use #embed para colocar o conteúdo de frase.txt dentro do array (lembre da vírgula antes do '\0'). O resultado deve ser a frase e (37 bytes): são 34 caracteres, mas o "ç" e o "ã" ocupam 2 bytes cada em UTF-8 (aula Acentos e UTF-8), mais 1 byte da quebra de linha no fim do arquivo.
Promoção: 3 cadernos por 10 reais! (37 bytes)
#include <stdio.h>
static const char frase[] = {
// coloque o #embed aqui
'\0'
};
int main(void) {
printf("%s", frase);
printf("(%zu bytes)\n", sizeof frase - 1);
return 0;
}
Promoção: 3 cadernos por 10 reais!
#include <stdio.h>
static const char frase[] = {
#embed "frase.txt"
, '\0'
};
int main(void) {
printf("%s", frase);
printf("(%zu bytes)\n", sizeof frase - 1);
return 0;
}
Resumo
- Versões: K&R (1978), C89/C90, C99, C11, C17, C23 e o C2y em preparo. Peça uma com
-std=c23; descubra com__STDC_VERSION__(202311Lno C23). O gcc 15 já usagnu23por padrão. - C99 trouxe
//,for (int i…),stdbool.h,stdint.h,snprintf. C11 trouxe_Generic,_Static_assert,_Noreturne removeu ogets. - C23:
bool/true/falsesem include,nullptr,constexpr,typeof/typeof_unqual,auto,0b1010,1'000,#embed,#elifdef,[[atributos]],static_assertsem mensagem,unreachable(),memset_explicit,strdup,%b. - No C23,
int f();quer dizer "sem parâmetros": código antigo que dependia disso não compila. - No editor do guia, o compilador entende o C23 inteiro, mas a biblioteca ainda não tem
%b,memset_explicit,strndupnemstdbit.h. - C2y:
0o17, laços com nome,_Genericcom tipo e outros já estão no rascunho;deferainda é proposta à parte.