Configurando o Visual Studio Code
Para compilar e executar programas em C no Visual Studio Code, devemos instalar algumas extensões. Recomendamos criar um perfil para o C e C++, o que manterá as configurações para essas linguagens separadas.
Para criar um perfil no Visual Studio Code, clique no ícone de engrenagem no canto inferior esquerdo e selecione Profiles (ou perfis).
Clique no botão New Profile. Uma nova entrada surgirá na lista de perfis.
Dê o nome C/C++ ao perfil.
Escolha o ícone de sua preferência.
Agora, selecione o perfil ao clicar no ícone de check ao lado da entrada dele na lista de perfis.
Extensões
Seção intitulada “Extensões”Tendo ativado o perfil C/C++, instale as seguinte extensões no Visual Studio Code:
- Git Graph: visualiza o histórico de commits do Git;
- C/C++: fornece suporte para desenvolvimento em C e C++;
- clangd: fornece recursos de análise de código para o Clang;
- CodeLLDB: permite a depuração de programas em C e C++.
Se você estiver usando o WSL, certifique-se de clicar nos botões Install in WSL: FedoraLinux-42 para cada extensão da lista de instaladas que oferecer essa opção.
Configurações
Seção intitulada “Configurações”Vamos adicionar algumas configurações padrão para o perfil C/C++.
Abra a paleta de comandos do Visual Studio Code com Preferences: Open User Settings (JSON), ou o equivalente em português.
Isso abrirá um arquivo chamado settings.json, responsável por definir as configurações desse perfil.
Toda vez que você muda alguma opção no menu de configurações do Visual Studio Code, o que ele faz é adicionar ou modificar uma linha nesse arquivo por baixo dos panos.
Copie o conteúdo a seguir e cole no arquivo settings.json aberto.
{ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2 }, "[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2 }, "[markdown]": { "editor.defaultFormatter": "DavidAnson.vscode-markdownlint", "editor.formatOnPaste": true, "editor.formatOnSave": true, "editor.tabSize": 2, "prettier.tabWidth": 2 }, "[snippets]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2 }, "C_Cpp.default.cppStandard": "c++23", "C_Cpp.default.cStandard": "c23", "C_Cpp.default.includePath": ["${workspaceFolder}/**"], "C_Cpp.default.intelliSenseMode": "clang-x64", "C_Cpp.intelliSenseEngine": "disabled", "cmake.configureArgs": [ "-DCMAKE_C_COMPILER=clang", "-DCMAKE_CXX_COMPILER=clang++" ], "cmake.debugConfig": { "console": "integratedTerminal", "cwd": "${workspaceFolder}", "externalConsole": false, "MIMode": "lldb", "stopAtEntry": false, "type": "lldb" }, "editor.formatOnSave": true, "editor.inlineSuggest.enabled": true, "editor.semanticHighlighting.enabled": true, "files.eol": "\n", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "launch": { "configurations": [ { "args": [], "cwd": "${workspaceFolder}", "name": "LLDB: build and launch C project (all files in root)", "preLaunchTask": "Clang: build C project (all files in root)", "program": "${workspaceFolder}/build/${workspaceFolderBasename}", "request": "launch", "terminal": "console", "type": "lldb" }, { "args": [], "cwd": "${workspaceFolder}", "name": "LLDB: build and launch C++ project (all files in root)", "preLaunchTask": "Clang: build C++ project (all files in root)", "program": "${workspaceFolder}/build/${workspaceFolderBasename}", "request": "launch", "terminal": "console", "type": "lldb" } ], "version": "0.2.0" }}Perceba que, abrindo o arquivo settings.json quando se usa o perfil C/C++, você verá as configurações específicas para este perfil, e não as configurações gerais do Visual Studio Code.
É este mesmo o objetivo que temos.
A configuração definida no arquivo settings.json faz o seguinte:
- O Clang é definido como o compilador padrão;
- Ativamos o IntelliSense para o Clang;
- As versões do C e do C++ são definidas como C23 e C++23, respectivamente;
- Definimos o formatador padrão como a extensão
clangd, e desativamos a formatação da extensãoC/C++; - Definimos a configuração de execução e depuração de programas compilados;
- Fazemos outras definições úteis.
Salve o arquivo e feche o Visual Studio Code.
Snippets
Seção intitulada “Snippets”Snippets são trechos de código que podem ser inseridos rapidamente no editor.
Eles possuem um atalho que, ao ser digitado e pressionado
Estamos utilizando o clang-format como formatador de texto e o clang-tidy como linter.
Para configurá-los, basta criar um arquivo .clang-format e um .clang-tidy na raiz do projeto.
Entretanto, criar e configurar esses arquivos manualmente pode ser trabalhoso. Por isso, podemos utilizar um snippet para criar esses arquivos automaticamente.
Configuração
Seção intitulada “Configuração”Garanta que você tenha selecionado o perfil C/C++.
Então abra a paleta de comandos do Visual Studio Code com Snippets: Configure Snippets.
Selecione a opção New Global Snippets file....
Digite o nome c_cpp e pressione
O arquivo de configuração de snippets para o perfil C/C++ será aberto.
Seu nome é c_cpp.code-snippets.
Este é o conteúdo padrão dele.
Apague todo o conteúdo dele.
Em seguida, copie o conteúdo a seguir e cole no arquivo c_cpp.code-snippets que foi aberto.
Lembre-se de salvar após a edição.
{ "Build task (C) (Local)": { "body": [ " {", " \"args\": [", " \"-fcolor-diagnostics\",", " \"-fansi-escape-codes\",", " \"-g\",", " \"\\${workspaceFolder}/*.c\",", " \"-I\",", " \"\\${workspaceFolder}\",", " \"-o\",", " \"\\${workspaceFolder}/build/\\${workspaceFolderBasename}\"", " ],", " \"command\": \"clang\",", " \"detail\": \"Tarefa de compilação de um projeto em C. Compila todos os arquivos C na raiz do projeto em um único executável.\",", " \"group\": {", " \"kind\": \"build\"", " },", " \"label\": \"Clang: build C project (Local)\",", " \"options\": {", " \"cwd\": \"\\${workspaceFolder}\"", " },", " \"problemMatcher\": [\"\\$gcc\"],", " \"type\": \"cppbuild\"", " },", ], "description": "Build a project in C if all files are in the root directory", "prefix": "c-build-task", }, "Build task (C++) (Local)": { "body": [ " {", " \"args\": [", " \"-fcolor-diagnostics\",", " \"-fansi-escape-codes\",", " \"-g\",", " \"\\${workspaceFolder}/*.cpp\",", " \"-I\",", " \"\\${workspaceFolder}\",", " \"-o\",", " \"\\${workspaceFolder}/build/\\${workspaceFolderBasename}\"", " ],", " \"command\": \"clang++\",", " \"detail\": \"Tarefa de compilação de um projeto em C++. Compila todos os arquivos C++ na raiz do projeto em um único executável.\",", " \"group\": {", " \"kind\": \"build\"", " },", " \"label\": \"Clang: build C++ project (Local)\",", " \"options\": {", " \"cwd\": \"\\${workspaceFolder}\"", " },", " \"problemMatcher\": [\"\\$gcc\"],", " \"type\": \"cppbuild\"", " },", ], "description": "Build a project in C++ if all files are in the root directory", "prefix": "cpp-build-task", }, "Clang Format configuration": { "body": [ "AccessModifierOffset: -4", "# AlignAfterOpenBracket: BlockIndent", "BasedOnStyle: Google", "BracedInitializerIndentWidth: 4", "ColumnLimit: 0", "ContinuationIndentWidth: 4", "EmptyLineAfterAccessModifier: Never", "EmptyLineBeforeAccessModifier: LogicalBlock", "FixNamespaceComments: true", "IndentAccessModifiers: true", "IndentCaseBlocks: true", "IndentCaseLabels: true", "IndentExternBlock: true", "IndentGotoLabels: true", "IndentPPDirectives: AfterHash", "IndentRequiresClause: true", "IndentWidth: 4", "InsertBraces: true", "IndentWrappedFunctionNames: true", "InsertNewlineAtEOF: true", "NamespaceIndentation: All", "ObjCBlockIndentWidth: 4", "PointerAlignment: Right", "PPIndentWidth: 4", "SeparateDefinitionBlocks: Always", "SpaceAfterCStyleCast: true", "SpaceAfterLogicalNot: false", "SpaceAfterTemplateKeyword: false", "SpaceBeforeAssignmentOperators: true", "SpaceBeforeCtorInitializerColon: false", "SpaceBeforeInheritanceColon: false", "SpaceBeforeParens: ControlStatements", "Standard: Latest", "TabWidth: 4", "UseTab: Never", "", ], "description": "Clang Format configuration", "prefix": "clang-format", }, "Clang Tidy configuration": { "body": [ "Checks: \"-*,readability-identifier-naming\"", "CheckOptions:", " # Macro", " - key: readability-identifier-naming.MacroDefinitionCase", " value: UPPER_CASE", " - key: readability-identifier-naming.MacroDefinitionPrefix", " value: \"_\"", " - key: readability-identifier-naming.MacroDefinitionIgnoredRegexp", " value: \"^[A-Z]+(_[A-Z]+)*_$\"", "", " # Default", " - key: readability-identifier-naming.VariableCase", " value: lower_case", "", " - key: readability-identifier-naming.StaticVariableCase", " value: lower_case", "", " - key: readability-identifier-naming.ParameterCase", " value: lower_case", "", " - key: readability-identifier-naming.FunctionCase", " value: camelBack", "", " - key: readability-identifier-naming.TypeAliasCase", " value: CamelCase", "", " - key: readability-identifier-naming.TypedefCase", " value: CamelCase", "", " - key: readability-identifier-naming.ConstantCase", " value: UPPER_CASE", "", " - key: readability-identifier-naming.StaticConstantCase", " value: lower_case", "", " - key: readability-identifier-naming.ConstexprVariableCase # Ensure the constexpr variables are treated as constants", " value: lower_case", " - key: readability-identifier-naming.ConstexprVariablePrefix", " value: \"\"", "", " # Class", " - key: readability-identifier-naming.ClassCase", " value: CamelCase", "", " - key: readability-identifier-naming.MemberCase", " value: lower_case", "", " # Enum", " - key: readability-identifier-naming.EnumCase", " value: CamelCase", "", " - key: readability-identifier-naming.EnumConstantCase", " value: UPPER_CASE", "", " # Struct", " - key: readability-identifier-naming.StructMemberCase", " value: lower_case", "", " # Namespace", " - key: readability-identifier-naming.NamespaceCase", " value: CamelCase", "", " - key: readability-identifier-naming.NamespaceConstantCase", " value: lower_case", "", " - key: readability-identifier-naming.ClassMemberCase", " value: lower_case", "", " # Global", " - key: readability-identifier-naming.GlobalConstantCase", " value: UPPER_CASE", "", ], "description": "Clang Tidy configuration", "prefix": "clang-tidy", }, "Debug launcher (C) (Local)": { "body": [ " {", " \"args\": [],", " \"cwd\": \"\\${workspaceFolder}\",", " \"name\": \"LLDB: build and launch C project (Local)\",", " \"preLaunchTask\": \"Clang: build C project (Local)\",", " \"program\": \"\\${workspaceFolder}/build/\\${workspaceFolderBasename}\",", " \"request\": \"launch\",", " \"terminal\": \"console\",", " \"type\": \"lldb\"", " },", ], "description": "Launch a program in C using LLDB", "prefix": "c-launch", }, "Debug launcher (C++) (Local)": { "body": [ " {", " \"args\": [],", " \"cwd\": \"\\${workspaceFolder}\",", " \"name\": \"LLDB: build and launch C++ project (Local)\",", " \"preLaunchTask\": \"Clang: build C++ project (Local)\",", " \"program\": \"\\${workspaceFolder}/build/\\${workspaceFolderBasename}\",", " \"request\": \"launch\",", " \"terminal\": \"console\",", " \"type\": \"lldb\"", " },", ], "description": "Launch a program in C++ using LLDB", "prefix": "cpp-launch", }, "Ignore auxiliary files on C and C++ projects.": { "body": ["## Build", ".cache/", "build/", ""], "description": "Ignore auxiliary files on C and C++ projects.", "prefix": "gitignore-c-cpp", }, "Launch file": { "body": [ "{", " \"configurations\": [],", " \"version\": \"0.2.0\"", "}", "", ], "description": "Launch file", "prefix": "launch-json", }, "Tasks file": { "body": [ "{", " \"version\": \"2.0.0\",", " \"tasks\": [", " ]", "}", "", ], "description": "Scheme of tasks.json file", "prefix": "tasks-json", },}Então, feche o Visual Studio Code.
Utilização
Seção intitulada “Utilização”Abra o VSCode no diretório separate_function que criamos anteriormente.
Crie um arquivo chamado .clang-format e outro chamado .clang-tidy na raiz do projeto.
A estrutura de pastas ficará como a seguir.
Directoryseparate_function
- .clang-format
- .clang-tidy
- .gitignore
- functions.c
- main.c
Em seguida, abra o arquivo .clang-format.
Dentro desse arquivo, digite clang-format e pressione
O arquivo .clang-format será preenchido com as configurações definidas no snippet Clang Format configurations.
Agora, faça o mesmo para o arquivo .clang-tidy.
Abra-o e digite clang-tidy, então pressione
Projeto
Seção intitulada “Projeto”Vamos criar um projeto para construir uma lista encadeada de nós.
No terminal, navegue para a pasta c_cpp_projects que criamos anteriormente.
cd ~/dev/c_cpp_projectsCrie um diretório chamado linked_nodes e navegue para dentro dele.
mkdir -p linked_nodescd linked_nodesAbra o Visual Studio Code no diretório atual.
code .Selecione o perfil C/C++ que criamos anteriormente.
Arquivos
Seção intitulada “Arquivos”Vamos criar arquivos dentro dessa pasta, de forma que o projeto ficará como a seguir.
Directorylinked_nodes
- main.c
- node.c
- node.h
Crie um arquivo chamado node.h e cole o seguinte código nele.
#ifndef __NODE_H__#define __NODE_H__
struct Node { int data; struct Node *next;};
struct Node *createNode();void setData(struct Node *node, int data);int getData(struct Node *node);void setNext(struct Node *node, struct Node *next);struct Node *getNext(struct Node *node);
#endif // __NODE_H__Então, crie um arquivo chamado node.c e cole o código a seguir.
#include "node.h"
#include <stdlib.h>
struct Node *createNode() { struct Node *new_node = (struct Node *) malloc(sizeof(struct Node)); if (new_node != NULL) { new_node->data = 0; new_node->next = NULL; } return new_node;}
void setData(struct Node *node, int data) { if (node != NULL) { node->data = data; }}
int getData(struct Node *node) { if (node != NULL) { return node->data; } return -1;}
void setNext(struct Node *node, struct Node *next) { if (node != NULL) { node->next = next; }}
struct Node *getNext(struct Node *node) { if (node != NULL) { return node->next; } return NULL;}Por fim, crie um arquivo chamado main.c e cole o código a seguir.
#include <stdio.h>#include <stdlib.h>
#include "node.h"
int main() { printf("Creating a linked list with 10 nodes\n");
struct Node *node = createNode(); struct Node *head = node; setData(node, 1);
for (int i = 2; i <= 10; i++) { struct Node *new_node = createNode(); setData(new_node, i); setNext(node, new_node); node = new_node; }
printf("Traversing the linked list\n");
node = head;
while (node != NULL) { printf("%d\t", getData(node)); node = getNext(node); }
printf("\n");
return 0;}Para configurar a formatação e o linter, crie os arquivos .clang-format e .clang-tidy na raiz do projeto.
Então utilize os snippets clang-format e clang-tidy para preenchê-los.
A estrutura do projeto ficará como a seguir.
Directorylinked_nodes
- .clang-format
- .clang-tidy
- main.c
- node.c
- node.h
Compilação
Seção intitulada “Compilação”Se você tiver ativado o perfil C/C++, o Visual Studio Code já deve reconhecer o projeto, identificando os arquivos de cabeçalho e de código, além das bibliotecas utilizadas.
Terminal
Seção intitulada “Terminal”Vamos compilar o projeto pelo terminal integrado do Visual Studio Code.
Dessa vez, criaremos uma pasta que guardará os arquivos de compilação.
Por convenção, daremos a ela o nome build.
Abra o terminal integrado com Terminal > New Terminal e execute os comandos abaixo.
mkdir -p buildclang main.c node.c -include node.h -o build/linked_nodesEsse comando compila os arquivos main.c e node.c, incluindo o arquivo de cabeçalho node.h, e gera o arquivo executável build/linked_nodes.
Para executar o programa, digite o comando abaixo e pressione
./build/linked_nodesO resultado da execução deve ser como o seguinte.
# dev/c_cpp_projects/linked_nodesmkdir -p buildclang main.c node.c -include node.h -o build/linked_nodes
# dev/c_cpp_projects/linked_nodes./build/linked_nodes# Creating a linked list with 10 nodes# Traversing the linked list# 1 2 3 4 5 6 7 8 9 10Queremos versionar o projeto por meio do Git. Entretanto, não queremos que os arquivos executáveis sejam enviados para o repositório.
Para garantirmos isso, crie um arquivo chamado .gitignore na raiz do projeto e use o snippet gitignore-c-cpp para preenchê-lo.
O conteúdo deve ser o seguinte.
## Build.cache/build/A estrutura do projeto ficará como a seguir.
Directorylinked_nodes
- .clang-format
- .clang-tidy
- .gitignore
- main.c
- node.c
- node.h
Como estamos compilando o projeto para dentro da pasta build, listamos ela no arquivo .gitignore.
Assim, quaisquer arquivos dentro dela não serão enviados para o repositório.
Além disso, o arquivo deve listar a pasta .cache/, que contém arquivos auxiliares da extensão clangd.
Para inicializar o repositório Git e fazer o primeiro commit, execute os comandos abaixo.
git initgit add .git commit -m "Initialize project"Interface gráfica
Seção intitulada “Interface gráfica”Agora, em vez de rodar o comando no terminal, vamos utilizar a interface gráfica do Visual Studio Code para compilar o projeto.
Crie uma pasta chamada .vscode na raiz do projeto.
Ela é responsável por guardar configurações específicas do Visual Studio Code para o projeto.
Dentro dela, crie um arquivo chamado tasks.json e copie para ele o conteúdo abaixo.
{ "tasks": [ { "args": [ "-fcolor-diagnostics", "-fansi-escape-codes", "-g", "${workspaceFolder}/*.c", "-I", "${workspaceFolder}", "-o", "${workspaceFolder}/build/${workspaceFolderBasename}" ], "command": "clang", "detail": "Tarefa de compilação de um projeto em C. Compila todos os arquivos C na raiz do projeto em um único executável.", "group": { "kind": "build" }, "label": "Clang: build C project (all files in root) (Local)", "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": ["$gcc"], "type": "cppbuild" } ], "version": "2.0.0"}A estrutura do projeto ficará como a seguir.
Directorylinked_nodes
Directory.vscode
- tasks.json
- .clang-format
- .clang-tidy
- .gitignore
- main.c
- node.c
- node.h
O que o arquivo faz é definir uma tarefa chamada Clang: build C project (all files in root) (Local).
Essa tarefa compila o projeto com o Clang, incluindo todos os arquivos de cabeçalho e todos os arquivos de código definidos na raiz do projeto.
O executável gerado terá o nome da pasta aberta no Visual Studio Code, linked_nodes, e será colocado dentro da pasta build.
Clique no arquivo main.c no Visual Studio Code para focar a visualização nele.
Abra a paleta de comandos com Tasks: Run Build Task.
Você também pode executar esse comando com o atalho
Selecione a tarefa Clang: build C project (all files in root) (Local).
O mesmo comando de compilação será executado, mas pelo Visual Studio Code. Ele exibirá o resultado da compilação no terminal integrado.
Para executar, podemos chamar o arquivo executável diretamente no terminal integrado.
Fique atento que não é possível interagir com essa sessão que compilou o projeto.
Você precisa criar uma nova sessão de terminal.
Então, digite ./build/linked_nodes e pressione
Configurações
Seção intitulada “Configurações”Felizmente, o Visual Studio Code permite que você salve as configurações de compilação em arquivos globais para serem utilizadas em outros projetos.
Ative o perfil C/C++, para que as configurações sejam salvas apenas para esse perfil.
Dessa forma, eliminamos o risco de conflitos entre diferentes configurações de compilação e depuração.
Para salvar as tarefas de compilação, abra a paleta de comandos com Tasks: Open User Tasks.
Selecione a opção Others.
Será aberto o arquivo padrão de tarefas do perfil C/C++.
Copie o conteúdo abaixo e cole no arquivo tasks.json aberto no Visual Studio Code.
Lembre-se de salvar.
{ "tasks": [ { "args": [ "-fcolor-diagnostics", "-fansi-escape-codes", "-g", "${workspaceFolder}/*.c", "-I", "${workspaceFolder}", "-o", "${workspaceFolder}/build/${workspaceFolderBasename}" ], "command": "clang", "detail": "Tarefa de compilação de um projeto em C. Compila todos os arquivos C na raiz do projeto em um único executável.", "group": { "kind": "build" }, "label": "Clang: build C project (all files in root)", "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": ["$gcc"], "type": "cppbuild" }, { "args": [ "-fcolor-diagnostics", "-fansi-escape-codes", "-g", "${workspaceFolder}/*.cpp", "-I", "${workspaceFolder}", "-o", "${workspaceFolder}/build/${workspaceFolderBasename}" ], "command": "clang++", "detail": "Tarefa de compilação de um projeto em C++. Compila todos os arquivos C++ na raiz do projeto em um único executável.", "group": { "kind": "build" }, "label": "Clang: build C++ project (all files in root)", "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": ["$gcc"], "type": "cppbuild" } ], "version": "2.0.0"}Assim, a tarefa estará disponível para todos os projetos que utilizarem o perfil C/C++.
Se você estiver desenvolvendo um projeto com outras pessoas que não fizeram a mesma configuração que você, então recomendo criar o arquivo tasks.json na pasta .vscode.
Assim, as configurações estarão disponíveis no repositório do projeto para todos, de forma que cada um possa compilar o projeto sem precisar configurar nada.