C++ Sintaxe

Sintaxe é o conjunto de regras de escrita de uma linguagem: onde vai cada símbolo, o que termina uma frase, o que separa uma parte da outra. Em português, um leitor entende "oi tudo bem" mesmo sem vírgula nem ponto de interrogação. O compilador de C++ não é assim tão tolerante: um ponto e vírgula a menos, uma letra maiúscula no lugar errado, e ele recusa o programa inteiro. Nesta aula você conhece as regras básicas, e também as liberdades que a linguagem dá.

Você vai aprender
  • O que é uma instrução e por que ela termina com ;.
  • Para que servem as chaves { } (os blocos).
  • Por que main e Main, cout e Cout são coisas diferentes.
  • O que o compilador ignora (espaços, linhas em branco, recuo) e o que ele não ignora.
  • Por que um texto entre aspas não pode quebrar de linha.
  • O que é o std::, o que faz o using namespace std; e por que o guia evita usá-lo.

Todos os programas foram compilados na máquina da Ana com o comando padrão do guia, g++ -std=c++23 -Wall -Wextra (aula Compilar com g++), com o g++ 15.2; alguns também com o clang++ 21.1, o compilador que o editor do guia usa.


A ideia: a gramática de uma receita

Uma receita tem uma estrutura: um título, uma lista de passos, cada passo numa frase que termina com ponto. "Bata os ovos. Junte o açúcar. Leve ao forno." Um programa em C++ é parecido:

Na receitaEm C++Exemplo
Uma frase com uma ordem ("Bata os ovos.")Uma instruçãostd::cout << "Oi\n";
O ponto finalO ponto e vírgula;
Um grupo de passos com título ("Massa:", "Cobertura:")Um bloco, entre chavesint main() { … }
As palavras, que precisam estar escritas certoOs nomes, em que maiúsculas importammain, std::cout

1. Instruções e o ponto e vírgula

Uma instrução (em inglês, statement) é uma ordem completa para o computador: "mostre isto", "guarde aquilo", "some estes números". Em C++, quase toda instrução termina com ;. Este programa tem duas:

#include <iostream>

int main() {
    std::cout << "Primeira instrução\n";
    std::cout << "Segunda instrução\n";
}

O ; é o que diz ao compilador onde uma instrução acaba e a próxima começa. Não é a quebra de linha: para o compilador, o fim da linha não significa nada. Por isso, isto também funciona, tudo numa linha só:

#include <iostream>
int main(){std::cout<<"Uma linha só!\n";std::cout<<"E funciona.\n";}
$ g++ -std=c++23 -Wall -Wextra umalinha.cpp -o umalinha && ./umalinha
Uma linha só!
E funciona.

Funciona, mas ninguém consegue ler. Escreva uma instrução por linha.

Onde não vai ponto e vírgula

  • Linhas que começam com #, como #include <iostream>. Elas são ordens para o pré-processador, não instruções de C++, e terminam no fim da linha.
  • Depois da } que fecha uma função, como a da main.
  • Depois de int main(), antes da {. Ali começa a função, não termina uma instrução.

E um ; sobrando? Um ; sozinho é uma "instrução vazia", que não faz nada. Este programa compila sem erro nem aviso:

#include <iostream>

int main() {
    std::cout << "Olá!\n";;
    ;
}
$ g++ -std=c++23 -Wall -Wextra pontos.cpp -o pontos && ./pontos
Olá!

Inofensivo aqui, mas não se acostume: mais adiante, um ; a mais logo depois de um if ou de um for muda o sentido do programa (você vai ver nas aulas if e else e for). O ; a menos é que dá erro, e ele está na seção Quando dá errado.


2. Blocos: as chaves { }

As chaves agrupam várias instruções num bloco. Você já conhece um: o corpo da main, que vai da { até a }. Um bloco pode ter outros blocos dentro, e vai ter, quando você aprender if, while e for. Dá até para abrir um bloco "solto":

#include <iostream>

int main() {
    std::cout << "Antes do bloco\n";
    {
        std::cout << "Dentro do bloco\n";
    }
    std::cout << "Depois do bloco\n";
}
$ g++ -std=c++23 -Wall -Wextra bloco.cpp -o bloco && ./bloco
Antes do bloco
Dentro do bloco
Depois do bloco

Aqui o bloco do meio não muda nada na saída. Ele só começa a fazer diferença com variáveis: o que é criado dentro de um bloco deixa de existir quando o bloco fecha (aula Escopo).

Três regras das chaves:

  1. Toda { tem a sua }, como parênteses numa conta. Uma chave sobrando ou faltando é erro (veja Lendo Erros do Compilador).
  2. A última que abriu é a primeira que fecha. No exemplo, a } da linha 7 fecha o bloco do meio; a da linha 9 fecha a main.
  3. Não vai ; depois da } de um bloco ou de uma função. (Há exceções, como as structs, que você verá no Nível 2.)

3. Maiúsculas e minúsculas fazem diferença

O C++ é sensível a maiúsculas e minúsculas (em inglês, case-sensitive). Para ele, main, Main e MAIN são três nomes diferentes, tão diferentes quanto main e banana. Quase tudo da linguagem e da biblioteca padrão se escreve em minúsculas: int, main, return, std, cout, include.

Veja o que acontece com uma maiúscula no lugar errado em cada parte do Olá, mundo.

Main em vez de main

#include <iostream>

int Main() {
    std::cout << "Olá!\n";
    return 0;
}
$ g++ -std=c++23 -Wall -Wextra Main.cpp -o Main
/usr/bin/x86_64-linux-gnu-ld.bfd: /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/Scrt1.o: na função "_start":
(.text+0x1b): referência não definida para "main"
collect2: error: ld returned 1 exit status

O compilador não reclamou de nada: Main é um nome válido para uma função qualquer. Quem reclamou foi o ligador (ld), a etapa final, que procura a função main para saber onde o programa começa e não a encontrou: "referência não definida para main" (em inglês, undefined reference to `main'). Esse tipo de erro, que aparece depois da compilação, é explicado em Lendo Erros do Compilador.

Cout em vez de cout

#include <iostream>

int main() {
    std::Cout << "Olá!\n";
}
$ g++ -std=c++23 -Wall -Wextra cout.cpp -o cout
cout.cpp: In function ‘int main()’:
cout.cpp:4:10: error: ‘Cout’ is not a member of ‘std’; did you mean ‘cout’?
    4 |     std::Cout << "Olá!\n";
      |          ^~~~
      |          cout

"Cout não é membro de std; você quis dizer cout?" O g++ percebeu que existe um nome muito parecido e sugeriu a correção, escrita embaixo da palavra errada. O Clang (o compilador do editor do guia) diz o mesmo com outras palavras:

$ clang++ -std=c++23 -Wall -Wextra cout.cpp -o cout
cout.cpp:4:10: error: no member named 'Cout' in namespace 'std'; did you mean 'cout'?
    4 |     std::Cout << "Olá!\n";
      |          ^~~~
      |          cout
/usr/lib/gcc/x86_64-linux-gnu/15/../../../../include/c++/15/iostream:65:18: note: 'cout' declared here
   65 |   extern ostream cout;          ///< Linked to standard output
      |                  ^
1 error generated.

STD e #Include

$ g++ -std=c++23 -Wall -Wextra STD.cpp -o STD          « STD::cout << "Olá!\n";
STD.cpp: In function ‘int main()’:
STD.cpp:4:5: error: ‘STD’ has not been declared
    4 |     STD::cout << "Olá!\n";
      |     ^~~

"STD não foi declarado": para o compilador, STD é um nome que ninguém criou.

$ g++ -std=c++23 -Wall -Wextra include.cpp -o include  « primeira linha: #Include <iostream>
include.cpp:1:2: error: invalid preprocessing directive #Include; did you mean #include?
    1 | #Include <iostream>
      |  ^~~~~~~
      |  include
include.cpp: In function ‘int main()’:
include.cpp:4:10: error: ‘cout’ is not a member of ‘std’
    4 |     std::cout << "Olá!\n";
      |          ^~~~
include.cpp:1:1: note: ‘std::cout’ is defined in header ‘<iostream>’; this is probably fixable by adding ‘#include <iostream>’
  +++ |+#include <iostream>
    1 | #Include <iostream>

Um erro só (o I maiúsculo) gerou dois. O primeiro é a causa: "diretiva de pré-processador inválida #Include; você quis dizer #include?". Como o iostream não foi incluído, o cout também "sumiu", e veio o segundo erro. Corrigindo o primeiro, os dois desaparecem. Essa é uma regra de ouro que você vai ver de novo: corrija sempre o primeiro erro primeiro.

Missão: este programa tem três maiúsculas no lugar errado. Rode, leia a primeira mensagem, corrija, e repita até ele mostrar as duas linhas. O editor usa o Clang, então as mensagens são parecidas com as do Clang acima.

#include <iostream>

int main() {
    std::Cout << "Bom dia, Ana!\n";
    Std::cout << "Hoje tem aula de C++.\n";
    Return 0;
}
#include <iostream>

int main() {
    std::cout << "Bom dia, Ana!\n";
    std::cout << "Hoje tem aula de C++.\n";
    return 0;
}
Dentro das aspas, vale o que você escrever

A regra das maiúsculas é para o código. O texto entre aspas é mostrado do jeito que está: "OLÁ", "olá" e "Olá" são três textos válidos, e cada um aparece na tela exatamente assim.


4. Espaços, linhas e recuo: o compilador não liga, mas você sim

Fora das aspas, o compilador trata espaços, tabulações e quebras de linha (os espaços em branco) como simples separadores. Um ou cem, tanto faz. Este programa "espalhado" compila e roda:

#include <iostream>

int
main
(
)
{
    std::cout
        <<
    "Espalhado, mas funciona.\n"
    ;
}
$ g++ -std=c++23 -Wall -Wextra espalhado.cpp -o espalhado && ./espalhado
Espalhado, mas funciona.

O espaço só é obrigatório onde ele separa duas palavras: int main não pode virar intmain. E ele é proibido dentro de um nome ou de um símbolo de dois caracteres: std::co ut, std: :cout e < < são erros.

O recuo (indentação) é para pessoas

Os quatro espaços antes de std::cout se chamam recuo ou indentação. O compilador os ignora, mas eles mostram, num relance, o que está dentro de quê. Compare:

Sem recuo (compila, mas confunde)Com recuo (o jeito certo)
int main() {
std::cout << "Antes\n";
{
std::cout << "Dentro\n";
}
std::cout << "Depois\n";
}
int main() {
    std::cout << "Antes\n";
    {
        std::cout << "Dentro\n";
    }
    std::cout << "Depois\n";
}

A regra: a cada {, o recuo aumenta um nível; a cada }, diminui. O guia usa 4 espaços por nível. Também é comum ver 2 espaços ou uma tabulação. Escolha um jeito e use sempre o mesmo. Os editores de código (Editores e IDEs) recuam sozinhos e têm um comando "formatar documento", que arruma tudo de uma vez (por baixo, muitos usam a ferramenta clang-format).

Onde fica a {?

Outra questão de gosto. O guia põe a chave de abertura no fim da linha (int main() {). Muitos projetos a põem sozinha na linha de baixo:

#include <iostream>

int main()
{
    std::cout << "Chave na linha de baixo também vale.\n";
}
$ g++ -std=c++23 -Wall -Wextra estilos.cpp -o estilos && ./estilos
Chave na linha de baixo também vale.

Os dois estilos são corretos. Em um projeto que já existe, siga o estilo dele.

O texto entre aspas não pode quebrar de linha

Dentro das aspas, os espaços contam (eles aparecem na tela) e a quebra de linha é proibida. Se você apertar Enter no meio de um texto:

#include <iostream>

int main() {
    std::cout << "Olá,
mundo!\n";
}
$ g++ -std=c++23 -Wall -Wextra quebra.cpp -o quebra
quebra.cpp:4:18: warning: missing terminating " character
    4 |     std::cout << "Olá,
      |                  ^
quebra.cpp:4:18: error: missing terminating " character
    4 |     std::cout << "Olá,
      |                  ^~~~~
quebra.cpp:5:7: error: stray ‘\’ in program
    5 | mundo!\n";
      |       ^
quebra.cpp:5:9: warning: missing terminating " character
    5 | mundo!\n";
      |         ^
quebra.cpp:5:9: error: missing terminating " character
    5 | mundo!\n";
      |         ^~
quebra.cpp: In function ‘int main()’:
quebra.cpp:5:1: error: ‘mundo’ was not declared in this scope
    5 | mundo!\n";
      | ^~~~~

"Falta o caractere " de fechamento" na linha 4. Depois disso, o compilador se perde: lê mundo como se fosse código e reclama de tudo na linha 5. Mais uma vez, o primeiro erro é o que importa.

Para quebrar um texto longo em várias linhas do código, feche as aspas e abra de novo na linha de baixo. Dois textos entre aspas lado a lado, separados só por espaços, viram um só:

#include <iostream>

int main() {
    std::cout << "Olá, "
                 "mundo!\n";
}
$ g++ -std=c++23 -Wall -Wextra juntas.cpp -o juntas && ./juntas
Olá, mundo!

Repare que a saída ficou numa linha só: quem quebra a linha na tela é o \n, não o Enter no código (aula Novas Linhas).


5. std:: e o using namespace std;

Tudo o que vem da biblioteca padrão tem o "sobrenome" std: std::cout, std::cin, std::string. Esse sobrenome é um namespace ("espaço de nomes"), uma espécie de bairro onde os nomes moram. Ele existe para evitar confusão: se você criar no seu programa algo chamado count, ele não briga com o std::count da biblioteca, porque moram em bairros diferentes.

Esquecer o sobrenome dá erro:

#include <iostream>

int main() {
    cout << "Olá!\n";
}
$ g++ -std=c++23 -Wall -Wextra semstd.cpp -o semstd
semstd.cpp: In function ‘int main()’:
semstd.cpp:4:5: error: ‘cout’ was not declared in this scope; did you mean ‘std::cout’?
    4 |     cout << "Olá!\n";
      |     ^~~~
      |     std::cout
In file included from semstd.cpp:1:
/usr/include/c++/15/iostream:65:18: note: ‘std::cout’ declared here
   65 |   extern ostream cout;          ///< Linked to standard output
      |                  ^~~~

"cout não foi declarado neste escopo; você quis dizer std::cout?" A note ainda mostra onde o std::cout de verdade está declarado, dentro do arquivo iostream da biblioteca. Você não precisa abrir esse arquivo; basta a sugestão.

O atalho: using namespace std;

Em muitos sites, livros e exercícios, você vai ver esta linha logo depois dos #include:

#include <iostream>
using namespace std;

int main() {
    cout << "Olá com using!\n";
}
$ g++ -std=c++23 -Wall -Wextra using.cpp -o using && ./using
Olá com using!
using
"Usando". Pede ao compilador que procure nomes em outro lugar também.
namespace
"Espaço de nomes": o que vem a seguir é um namespace inteiro, não um nome só.
std
O namespace da biblioteca padrão.
;
É uma instrução, então termina com ponto e vírgula.

Em português: "a partir daqui, quando eu escrever um nome solto e você não achar, procure também no std". É como derrubar o muro entre o seu bairro e o bairro std. Funciona, e economiza digitação. O problema é que a biblioteca padrão tem milhares de nomes, muitos deles palavras comuns em inglês: size, count, max, list, data. Com o muro derrubado, um nome seu pode trombar com um deles. A Ana criou uma variável chamada size ("tamanho"):

#include <iostream>
using namespace std;

int size = 3;

int main() {
    cout << "Tamanho: " << size << "\n";
}
$ g++ -std=c++23 -Wall -Wextra ambiguo.cpp -o ambiguo
ambiguo.cpp: In function ‘int main()’:
ambiguo.cpp:7:28: error: reference to ‘size’ is ambiguous
    7 |     cout << "Tamanho: " << size << "\n";
      |                            ^~~~
In file included from /usr/include/c++/15/string:55,
                 from /usr/include/c++/15/bits/locale_classes.h:42,
                 from /usr/include/c++/15/bits/ios_base.h:43,
                 from /usr/include/c++/15/ios:46,
                 from /usr/include/c++/15/bits/ostream.h:43,
                 from /usr/include/c++/15/ostream:42,
                 from /usr/include/c++/15/iostream:43,
                 from ambiguo.cpp:1:
/usr/include/c++/15/bits/range_access.h:284:5: note: candidates are: ‘template<class _Tp, long unsigned int _Nm> constexpr std::size_t std::size(const _Tp (&)[_Nm])’
  284 |     size(const _Tp (&)[_Nm]) noexcept
      |     ^~~~
/usr/include/c++/15/bits/range_access.h:274:5: note:                 ‘template<class _Container> constexpr decltype (__cont.size()) std::size(const _Container&)’
  274 |     size(const _Container& __cont) noexcept(noexcept(__cont.size()))
      |     ^~~~
ambiguo.cpp:4:5: note:                 ‘int size’
    4 | int size = 3;
      |     ^~~~

Assustador, mas a primeira linha de erro resume tudo: "a referência a size é ambígua". O compilador achou dois size: o da Ana (a última note, linha 4) e o std::size, uma função da biblioteca que ela nem sabia que existia (as note do meio mostram onde ele mora, dentro dos arquivos que o iostream puxa). Ele não sabe qual usar e desiste. Sem o using namespace std;, o mesmo programa (com std::cout) compila sem problema, porque o size da Ana e o std::size continuam em bairros separados.

Em programas de 10 linhas, o risco é pequeno. Em programas grandes, com vários arquivos e bibliotecas, essas trombadas aparecem de repente, às vezes quando você atualiza o compilador e a biblioteca ganha um nome novo. Num arquivo de cabeçalho (.h), o using namespace std; é pior ainda, porque derruba o muro em todo arquivo que o incluir (aula Arquivos .h e .cpp).

Formas de escrever, e qual usar

FormaExemploQuando
Nome completostd::cout << "Oi\n";A forma do guia. Sempre claro de onde o nome vem.
Trazer um nome sóusing std::cout; e depois cout << "Oi\n";Quando um nome se repete muito num arquivo .cpp. Traz só ele, não os milhares.
Trazer o namespace inteirousing namespace std;Exercícios curtos e código de outras pessoas. Evite em programas grandes e nunca use em .h.
#include <iostream>
using std::cout;

int main() {
    cout << "Só o cout veio para cá.\n";
}
$ g++ -std=c++23 -Wall -Wextra usingcout.cpp -o usingcout && ./usingcout
Só o cout veio para cá.

Os namespaces (inclusive como criar os seus) têm aula própria no Nível 2: Namespaces.


Quando dá errado

error: expected ‘;’ before …
#include <iostream>

int main() {
    std::cout << "Olá, mundo!\n"
}
$ g++ semponto.cpp -o semponto
semponto.cpp: In function ‘int main()’:
semponto.cpp:4:33: error: expected ‘;’ before ‘}’ token
    4 |     std::cout << "Olá, mundo!\n"
      |                                 ^
      |                                 ;
    5 | }
      | ~                                

O que significa: "esperava ; antes de }". Uma instrução não foi terminada. O g++ indica o lugar e até desenha o ; que falta.

Como consertar: ponha o ; no fim da instrução indicada. Se a linha apontada parece certa, olhe o fim da linha de cima.

‘Cout’ is not a member of ‘std’; did you mean ‘cout’?

O que significa: um nome da biblioteca foi escrito com maiúscula (ou com uma letra trocada). Mensagens com did you mean ("você quis dizer") trazem a correção pronta.

Como consertar: escreva o nome como sugerido, em minúsculas.

‘cout’ was not declared in this scope; did you mean ‘std::cout’?

O que significa: faltou o std:: na frente do nome.

Como consertar: escreva std::cout. (O using namespace std; também "resolve", mas traz os riscos da seção 5.)

referência não definida para "main" / undefined reference to `main'

O que significa: o programa não tem uma função chamada exatamente main. Quase sempre é Main, mian ou MAIN.

Como consertar: int main(), tudo em minúsculas.

missing terminating " character

O que significa: um texto abriu aspas e não fechou na mesma linha. Ou faltou a " final, ou você quebrou a linha no meio do texto.

Como consertar: feche as aspas na mesma linha. Para textos longos, use dois textos lado a lado ("Olá, " "mundo!\n").

reference to ‘size’ is ambiguous

O que significa: com using namespace std;, um nome seu ficou igual a um nome da biblioteca padrão.

Como consertar: tire o using namespace std; e use std::, ou dê outro nome à sua variável (tamanho, em vez de size).


Referência rápida

RegraCertoErrado
Instrução termina com ;std::cout << "Oi\n";std::cout << "Oi\n"
Sem ; em linhas com ##include <iostream>#include <iostream>; (o g++ avisa: extra tokens at end of ‘#include’ directive)
Toda { tem sua }int main() { … }int main() { …
Maiúsculas importammain, std::cout, returnMain, std::Cout, Return
Espaços e linhas: livres fora das aspasstd::cout << "Oi\n";std::co ut, < <
Texto não quebra de linha"Olá, " "mundo""Olá, + Enter + mundo"
Recuo de 4 espaços por blocoNão muda o programa; muda quem lê
Nomes da biblioteca com std::std::coutcout (sem using)

Exercícios

1. O que falta?

Complete o símbolo que termina esta instrução:

std::cout << "Bom dia!\n"

2. O sobrenome

Complete para usar o cout da biblioteca padrão sem using:

cout << "Oi\n";

3. Trazer um nome só

Complete para trazer só o cout para o seu arquivo (e não o namespace inteiro):

std::cout;

4. Qual destas linhas compila?

5. O que o compilador faz com o recuo (os espaços no começo das linhas)?

6. Por que o guia evita using namespace std;?

Missão final: arrume a bagunça

Missão: a Ana escreveu este programa com pressa. Ele tem um erro de maiúscula, um ; faltando e usa using namespace std;. Faça ele mostrar as três linhas, sem o using namespace std; (use std::cout), e arrume o recuo para 4 espaços.

Lista da feira
- tomate
- alface
#include <iostream>
using namespace std;
int main() {
cout << "Lista da feira\n"
  Cout << "- tomate\n";
        cout << "- alface\n";
}
#include <iostream>

int main() {
    std::cout << "Lista da feira\n";
    std::cout << "- tomate\n";
    std::cout << "- alface\n";
}

Resumo

  • Uma instrução é uma ordem completa e termina com ;. Linhas com # e a } de uma função não levam ;.
  • Blocos agrupam instruções entre { }. Toda chave aberta precisa ser fechada.
  • Maiúsculas importam: main, std::cout, return, #include, tudo em minúsculas.
  • Espaços, linhas em branco e recuo não mudam o programa, mas mudam muito a leitura. Use 4 espaços por nível.
  • Um texto entre aspas não pode quebrar de linha no código; para isso, use dois textos lado a lado.
  • std:: é o "sobrenome" da biblioteca padrão. using namespace std; derruba o muro e pode causar trombadas de nomes; o guia usa std::.
  • Corrija sempre o primeiro erro: muitas vezes ele causa os outros.