Ir para o conteúdo

Última atualização:2026-10-12

Notas de desenvolvimento com libcurl em C++

Um estilo de código uniforme facilita a colaboração da equipe e a revisão de código; o mais usado na indústria é o estilo do google. Nesta seção, algo diferente: vamos ver como é o padrão de código da equipe do curl, uma ferramenta que usamos com muita frequência.

Sobre o curl, em resumo: ele é muito útil para transferir dados em linha de comando ou em scripts, e você certamente já o usou; sua implementação pode ser consultada no github

https://github.com/curl/curl

A seguir, vamos olhar as normas de desenvolvimento em C do curl por vários ângulos.

Nomenclatura

Nomes novos de funções e variáveis devem ser lógicos, compreensíveis e nomeados de acordo com sua finalidade.

Funções locais de arquivo devem ser declaradas como estáticas, e recomenda-se usar nomes em letras minúsculas.

Indentação

Use apenas espaços para indentar, nunca tabulações. Cada nova chave de abertura usa dois espaços.

if(something_is_true) {
  while(second_statement == fine) {
    moo();
  }
}

Comentários

Como se escreve código C89, não são permitidos comentários //. Eles só foram introduzidos no padrão C99. Use apenas /* comentários */.

/* 这是一个注释 */

Linhas longas

O código-fonte do curl nunca deve ultrapassar 79 colunas; mesmo na era das telas grandes e de alta resolução, ainda há dois motivos para manter isso:

  1. Colunas mais estreitas são mais fáceis de ler que colunas largas. Há um motivo pelos quais os jornais usam colunas há décadas, até séculos.
  2. Colunas mais estreitas permitem que os desenvolvedores exibam mais facilmente vários trechos de código lado a lado em janelas diferentes. Isso permite mostrar dois ou três arquivos de código-fonte lado a lado na mesma tela — além de vários terminais e janelas de depuração.

Chaves

Em expressões if/while/do/for, escrevemos a chave de abertura na mesma linha da palavra-chave e colocamos a chave de fechamento em uma linha no mesmo nível de indentação da palavra-chave inicial. Assim:

if(age < 40) {
  /* 显然是年轻人 */
}
Se contiverem apenas uma instrução de uma linha, as chaves podem ser omitidas:

if(!x)
  continue;
Para funções, a chave de abertura deve ficar em uma linha separada:

int main(int argc, char **argv)
{
  return 1;
}

'else' na linha seguinte

Ao adicionar uma cláusula else a uma expressão condicional usando chaves, adicionamo-la em uma nova linha após a chave de fechamento. Assim:

if(age < 40) {
  /* 显然是年轻人 */
}
else {
  /* 可能是脾气暴躁的 */
}

Sem espaço antes dos parênteses

Ao usar expressões if/while/do/for, não deve haver espaço entre a palavra-chave e o parêntese de abertura. Assim:

while(1) {
  /* 永远循环 */
}

Usar condições booleanas

Em condições if/while, preferimos testar o valor da condição, como booleanos com TRUE ou FALSE, ponteiros com NULL ou != NULL, e inteiros com zero ou diferente de zero, em vez de:

result = do_something();
if(!result) {
  /* 出现了问题 */
  return result;
}

Não atribuir dentro de condições

Para aumentar a legibilidade e reduzir a complexidade das condições, evite atribuições de variáveis em condições if/while. Este estilo é desaprovado:

if((ptr = malloc(100)) == NULL)
  return NULL;
Prefira expressar com mais clareza:

ptr = malloc(100);
if(!ptr)
  return NULL;

Novo bloco em nova linha

Nunca se escrevem vários comandos na mesma linha, nem mesmo para condições if() curtas.

if(a)
  return TRUE;
else if(b)
  return FALSE;
Nunca assim:

if(a) return TRUE;
else if(b) return FALSE;

Espaços ao redor dos operadores

Use espaços nos dois lados dos operadores em expressões C. Exceto os operadores de sufixo (), [], ->, ., ++, -- e os unários +, -, !, ~, &, que não devem ter espaços.

Exemplo:

bla = func();
who = name[0];
age += 1;
true = !false;
size += -2 + 3 *

 (a + b);
ptr->member = a++;
struct.field = b--;
ptr = &address;
contents = *pointer;
complement = ~bits;
empty = (!*string) ? TRUE : FALSE;

Valor de retorno sem parênteses

Não coloque parênteses extras no comando 'return':

int works(void)
{
  return TRUE;
}

Parâmetro de sizeof com parênteses

Ao usar o operador sizeof no código, preferimos colocar parênteses ao redor do seu argumento:

int size = sizeof(int);

Alinhamento de colunas

Alguns comandos não podem ser completos em uma única linha porque a linha é longa demais, o comando é difícil de ler, ou por outras diretrizes de estilo acima. Nesses casos, o comando se estende por várias linhas.

Se uma linha contínua faz parte de uma expressão ou subexpressão, você deve alinhá-la na coluna adequada para que se perceba claramente de qual parte do comando ela faz. Os operadores não devem começar em linhas contínuas. Nos demais casos, siga a diretriz de indentação de 2 espaços. Aqui estão alguns exemplos do libcurl:

if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
   (handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
   (handle->set.httpreq == HTTPREQ_GET ||
    handle->set.httpreq == HTTPREQ_HEAD))
  /* 没有要求 HTTP/1.0 并且是 GET 或 HEAD 请求 */
  return TRUE;
Sem parênteses, use a indentação padrão:

data->set.http_disable_hostname_check_before_authentication =
  (0 != va_arg(param, long)) ? TRUE : FALSE;
Em chamadas de função, use o parêntese de abertura:

if(option) {
  result = parse_login_details(option, strlen(option),
                               (userp ? &user : NULL),
                               (passwdp ? &passwd : NULL),
                               NULL);
}
Alinhe com o parêntese "atualmente aberto":

DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
             "server response left\n",
             (int)clipamount));

Código dependente de plataforma

Use #ifdef HAVE_FEATURE para código condicional. Evitamos verificar um sistema operacional ou hardware específico em linhas #ifdef. HAVE_FEATURE deve ser gerado pelo script configure para sistemas do tipo Unix, e eles são definidos diretamente nos arquivos config-[system].h de outros sistemas.

Também incentivamos o uso, quando o libcurl é compilado, de macros/funções que podem ser vazias ou definidas como constantes, para que o código fique sem emendas. Como neste exemplo, em que a função magic() funciona de forma diferente conforme as condições da compilação:

#ifdef HAVE_MAGIC
void magic(int a)
{
  return a + 2;
}
#else
#define magic(x) 1
#endif

int content = magic(3);

Não use typedef em estruturas

Embora seja possível usar estruturas, não faça typedef delas. Identifique-as com a forma struct name:

struct something {
   void *valid;
   size_t way_to_write;
};
struct something instance;
Não assim:

typedef struct {
   void *wrong;
   size_t way_to_write;
} something;
something instance;
Este artigo foi traduzido de: https://curl.se/dev/code-style.html

Nota

Este texto serve como memorando de desenvolvimento; recomenda-se consultá-lo junto com a documentação oficial do libcurl e a análise dos códigos de erro do projeto específico.

Tópicos relacionados

Comentários