Federico Mena-Quintero
federico@gnome.org 2013
A equipe do GTK+
Nossas diretrizes para código C no GNOME
Rafael Fontenelle
rafaelff@gnome.org 2017

# Estilo de codificação C

Esse documento apresenta o estilo de codificação preferido para programas C no GNOME. Enquanto o estilo de codificação é muito uma questão de gosto, no GNOME somos a favor de um estilo de codificação que promove consistência, legibilidade e manutenção.

Nós apresentamos exemplos de bom estilo de codificação, bem como exemplos de estilo ruim que não é aceitável no GNOME. Por favor, tente enviar patches que estejam em conformidade com o estilo de codificação do GNOME; isso indica que você fez seu dever de casa para respeitar o objetivo do projeto de manutenção a longo prazo. Patches com o estilo de codificação do GNOME também serão mais fáceis de revisar!

Esse documento é para código C. Para outras linguagens, veja a página principal das Diretrizes de programação do GNOME.

Essas diretrizes são fortemente inspiradas no documento “CODING-STYLE” do GTK, no “CodingStyle” do Kernel Linux e no “GNU Coding Standards”. Essas são pequenas variações entre si, com modificações particulares para cada culturas e necessidades em particular do projeto, e a versão do GNOME não é diferente.

# A regra mais importante

A regra mais importante quando se está escrevendo código é essa: veja o código ao redor e tente imitá-lo.

Como um mantenedor, é assustador receber um patch que obviamente está em um estilo de codificação diferente do código ao redor. Isso é desrespeitoso, como alguém pisando em uma casa impecavelmente limpa com sapatos cheios de lama.

Então, independente do que este documenta recomenda, se há código escrito e você está fazendo um patch para ele, mantenha a consistência do seu estilo atual ainda que não seja seu estilo favorito.

# Largura da linha

Tente usar linhas de códigos entre 80 e 120 caracteres. Essa quantidade de texto é fácil de ajustar na maioria dos monitores com um tamanho de fonte decente. Linhas maiores que isso se tornam difíceis de ler, e isso pode significar que você provavelmente deveria restruturar seu código. Se você tiver um número grande de níveis de recuo, isso significa que você provavelmente deveria corrigir seu código de qualquer maneira.

# Recuo

Em geral, há dois estilos de recuo preferidos para código no GNOME.

Estilo do Kernel Linux. Tabulações com um comprimento de 8 caracteres são usados para recuo, com colocação de chaves de K&R:

for (i = 0; i < num_elements; i++) { foo[i] = foo[i] + 42;

if (foo[i] < 35) { printf ("Foo!"); foo[i]--; } else { printf ("Bar!"); foo[i]++; } }

Estilo GNU. Cada novo nível possui recuo de 2 espaços, aspas vai em uma linha própria e elas também possuem recuo.

for (i = 0; i < num_elements; i++) { foo[i] = foo[i] + 42;

if (foo[i] < 35) { printf ("Foo!"); foo[i]--; } else { printf ("Bar!"); foo[i]++; } }

Ambos estilos têm suas vantagens e desvantagens. O mais importante é ser consistente com o código ao redor. Por exemplo, a biblioteca GTK+, que é uma caixa de ferramentas de widgets do GNOME, é escrito com o estilo GNU. Nautilus, o gerenciador de arquivos do GNOME, é escrito no estilo Kernel Linux. Ambos estilos são perfeitamente legíveis e consistentes quando você se acostuma com eles.

Seu primeiro sentimento ao ter que estudar ou trabalhar em um pedaço de código que não seja seu preferido em estilo de recuo pode ser, como vamos colocá-lo, desconfortável. Você deve resistir sua inclinação em ajustar o recuo de tudo, ou usar um estilo inconsistente para seu patch. Lembre-se da primeira regra: ser consistente e respeitoso com os costumes do código, e seus patches terão uma chance muito mais alta de serem aceitos sem muita argumentação sobre o estilo de recuo correto.

# Caracteres de tabulações

Não altere o tamanho dos tabs em seu editor; deixe-os como 8 espaços. Alterar o tamanho dos tabs naquele código que você não escreveu estará perpetuamente desalinhada.

Em vez disso, defina o tamanho do recuo conforme apropriado para o código que você está editando. Quando se está escrevendo em algo diferente do estilo Kernel Linux, você pode está querer dizer ao seu editor para converter todas os tabs para 8 espaços, de forma que não haja ambiguidade sobre a quantidade de espaços.

# Chaves

Chaves não devem ser usadas para blocos de instrução singular:

/* válido */ if (condição) single_statement (); else another_single_statement (arg1);

A regra de “nenhum bloco para instruções singulares” possui apenas quatro exceções:

No estilo GNU, se qualquer um dos lados de uma instrução if-else possui chaves, ambos lados deveriam ter, para corresponder o recuo:

/* estilo GNU válido */ if (condição) { foo (); bar (); } else { baz (); }
/* inválido */ if (condição) { foo (); bar (); } else baz ();

Se a instrução singular cobre múltiplas linhas (ex.: para funções com muitos argumentos) e é seguido por `else` ou `eles if`:

/* estilo Kernel Linux válido */ if (condição) { uma_instrução_singular_com_muitos_args (algum_argumento_comprido, outro_argumento_comprido, e_mais_um_outro, mais_um); } else outro_arg_singular (arg1, arg2);

/* estilo GNU válido */ if (condição) { uma_instrução_singular_com_muitos_args (algum_argumento_comprido, outro_argumento_comprido, e_mais_um_outro, mais_um); } else { outro_arg_singular (arg1, arg2); }

Se a condição for composta de muitas linhas:

/* estilo Kernel Linux válido */ if (condição1 || (condição2 && condição3) || condição4 || (condição5 && (condição6 || condição7))) { uma_instrução_singular (); }

/* estilo GNU válido */ if (condição1 || (condição2 && condição3) || condição4 || (condição5 && (condição6 || condição7))) { uma_instrução_singular (); }

Note que tais condições longas são geralmente difíceis de entender. Uma boa prática é definir essa condição para uma variável booleana, com um bom nome para aquela variável. Uma outra forma é mover a condição longa para uma função.

`if`s aninhados, caso em que o bloco deve ser colocado `if` mais extremo:

/* estilo Kernel Linux válido */ if (condição) { if (outra_condição) instrução_singular (); else outra_instrução_singular (); }

/* estilo GNU válido */ if (condição) { if (outra_condição) instrução_singular (); else outra_instrução_singular (); }
/* inválido */ if (condição) if (outra_condição) instrução_singular (); else if (mais_uma_condição) outra_instrução_singular ();

Em geral, novos blocos devem ser colocados em um novo nível de recuo, como este:

int retval = 0;

instrucao_1 (); instrucao_2 ();

{ int var1 = 42; gboolean res = FALSE;

res = instrucao_3 (var1);

retval = res ? -1 : 1; }

Enquanto chaves para definições de função devem ficar em uma nova linha, elas não devem adicionar um novo nível de recuo:

/* estilo Kernel Linux válido */ static void minha_funcao (int argumento) { faz_minhas_coisas (); }

/* estilo GNU válido */ static void minha_funcao (int argumento) { faz_minhas_coisas (); }
/* inválido */ static void minha_funcao (int argumento) { faz_minhas_coisas (); }

/* inválido */ static void minha_funcao (int argumento) { faz_minhas_coisas (); }

# Condições

Não verifique valores booleanos por igualdade. Ao usar comparações implícitas, o código resultante pode ser mais parecido com o inglês conversacional. Um outro fundamento é que um valor ‘verdadeiro’ não necessariamente será igual a macro `TRUE` usada. Por exemplo:

/* inválido */ if (localizado == TRUE) fazer_foo ();

/* inválido */ if (localizado == FALSE) fazer_bar ();
/* válido */ if (localizado) fazer_foo ();

/* válido */ if (!localizado) fazer_bar ();

A linguagem C usa o valor 0 para muitos propósitos. Como um valor numérico, o fim de uma string, um ponteiro nulo e o booleano `FALSE`. Para tornar o código mais limpo, você deveria escrever código que realça a forma específica que 0 é usado. Então, ao ler uma comparação, é possível saber o tipo de variável. Para variáveis booleanas, uma comparação implícita é apropriado porque já é uma expressão lógica. Outros tipos de variáveis que não são expressões lógicas por si só, então uma comparação explícita é melhor:

/* válido */ if (algum_ponteiro == NULL) fazer_blá ();

/* válido */ if (número == 0) fazer_foo ();

/* válido */ if (str != NULL && *str != '\0') fazer_bar ();
/* inválido */ if (!algum_ponteiro) fazer_blá ();

/* inválido */ if (!número) fazer_foo ();

/* inválido */ if (str && *str) fazer_bar ();

# Funções

Funções devem ser declaradas colocando o valor de retorno em uma linha separada do nome da função:

void minha_funcao (void) { … }

A lista de argumentos deve estar quebrada em nova linha para cada argumento, com os nomes dos argumentos alinhados à direita, levando em consideração os ponteiros:

void minha_funcao (algum_tipo_t tipo, outro_tipo_t *um_ponteiro, double_ptr_t **ponteiro_duplo, tipo_final_t outro_tipo) { … }

Se você usa Emacs, você pode usar `M-x align` para fazer esse tipo de alinhamento automaticamente. Basca colocar o ponteiro e marcar em volta do protótipo da função e invocar aquele comando.

O alinhamento também se mantém ao invocar uma função sem quebrar o limite de comprimento da linha:

alinha_args_de_funcoes (primeiro_argumento, segundo_argumento, terceiro_argumento);

# Espaço em branco

Sempre coloque espaço antes de abrir parênteses, mas nunca após:

/* válido */ if (condição) faz_minhas_coisas ();

/* válido */ switch (condição) { }
/* inválido */ if(condição) faz_minhas_coisas();

/* inválido */ if ( condição ) faz_minhas_coisas ( );

Ao declarar um tipo de estrutura, use novas linhas para separar seções lógicas da estrutura:

struct _GtkWrapBoxPrivate { GtkOrientation orientation; GtkWrapAllocationMode mode;

GtkWrapBoxSpreading horizontal_spreading; GtkWrapBoxSpreading vertical_spreading;

guint16 vertical_spacing; guint16 horizontal_spacing;

guint16 minimum_line_children; guint16 natural_line_children;

GList *children; };

Não elimine espaços em branco e novas linhas apenas por que alguma coisa caberia em uma única linha:

/* inválido */ if (condição) foo (); else bar ();

Elimine espaços em branco de qualquer linha, preferivelmente como um patch ou commit separado. Nunca use linhas vazias no começo ou no fim de um arquivo.

Essa é uma pequena função de Emacs que você pode usar para limpar linhas terminando com espaço em branco:

(defun clean-line-ends () (interactive) (if (not buffer-read-only) (save-excursion (goto-char (point-min)) (let ((count 0)) (while (re-search-forward "[ ]+$" nil t) (setq count (+ count 1)) (replace-match "" t t)) (message "Limpadas %d linhas" count)))))

# A instrução `switch`

Um `switch` deve abrir um bloco em um novo nível de recuo, e cada `case` deve iniciar no mesmo nível de recuo que as chaves, com o bloco de `case` em um novo nível de recuo:

/* estilo Kernel Linux válido */ switch (condição) { case FOO: fazer_foo (); break;

case BAR: fazer_bar (); break; }

/* estilo GNU válido */ switch (condição) { case FOO: fazer_foo (); break;

case BAR: fazer_bar (); break; }
/* inválido */ switch (condição) { case FOO: fazer_foo (); break; case BAR: fazer_bar (); break; }

/* inválido */ switch (condição) { case FOO: fazer_foo (); break; case BAR: fazer_bar (); break; }

/* inválido */ switch (condição) { case FOO: fazer_foo (); break; case BAR: fazer_bar (); break; }

É preferível, apesar de não ser obrigatório, separar os vários cases com uma nova linha:

switch (condição) { case FOO: fazer_foo (); break;

case BAR: fazer_foo (); break;

default: fazer_padrão (); }

A instrução `break` para o caso `default` não é obrigatório.

Se alternando sobre um tipo enumerado, uma instrução `case` deve existir para cada novo membro do tipo enumerado. Para membros que você não deseja tratar, apelide suas instruções `case` para `default`:

switch (condição_enumerada) { case TRATADA_1: fazer_foo (); break;

case TRATADA_2: fazer_bar (); break;

case IGNORADA_1: case IGNORADA_2: default: fazer_padrão (); }

Se a maioria dos membros do tipo enumerado não deve ser tratada, considere usar uma instrução `if` em vez de um `switch`.

Se um bloco `case` precisa declarar novas variáveis, as mesmas regras que os blocos internos se aplicam (veja acima); a instrução `break` deve ser colocada fora do bloco interno:

/* estilo GNU válido */ switch (condição) { case FOO: { int foo;

foo = fazer_foo (); } break;

… }

# Arquivos de cabeçalho

A única regra importante para cabeçalhos é que as definições de funções devem estar alinhados verticalmente em três colunas:

tipo_retorno nome_funcao (tipo argumento, tipo argumento, tipo argumento);

A largura máxima de cada coluna é dada pelo elemento mais longo na coluna:

void gtk_type_set_property (GtkType *type, const gchar *value, GError **error); const gchar *gtk_type_get_property (GtkType *type);

Também é possível alinhar as colunas à próxima tabulação:

void gtk_type_set_prop (GtkType *type, gfloat value); gfloat gtk_type_get_prop (GtkType *type); gint gtk_type_update_foobar (GtkType *type);

Como anteriormente, você pode usar `M-x align` no Emacs para fazer isso automaticamente.

Se você está criando uma biblioteca pública, tente exportar um único arquivo de cabeçalho público que, por sua vez, inclua todos os arquivos de cabeçalhos menores nele. Isto é para que cabeçalhos públicos nunca seja incluídos diretamente; em vez disso, uma única inclusão é usada nos aplicativos. Por exemplo, GTK+ usa o seguinte em seus arquivos de cabeçalhos que não devem ser incluídos diretamente por aplicativos:

#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) #error "Only <gtk/gtk.h> can be included directly." #endif

Para bibliotecas, todos cabeçalhos devem ter proteções de inclusão (para uso interno) e proteções de C++ ou, em inglês, #include guards e C++ guards. Estas fornece a mágica `extern "C"` que C++ requer para incluir cabeçalhos de C simples:

#ifndef MYLIB_FOO_H_ #define MYLIB_FOO_H_

#include <gtk/gtk.h>

G_BEGIN_DECLS

…

G_END_DECLS

#endif /* MYLIB_FOO_H_ */

# Classes de GObject

Definições e implementações de classe GObject exigem algumas notas adicionais de estilo de codificação, e devem sempre estar sob espaço de nome correto.

Declarações `Typedef` devem ser colocadas no começo do arquivo:

typedef struct _GtkBoxedStruct GtkBoxedStruct; typedef struct _GtkMoreBoxedStruct GtkMoreBoxedStruct;

Isso inclui tipos de enumeração:

typedef enum { GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT, GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH } GtkSizeRequestMode;

A tipos de retorno de chamada (callback):

typedef void (* GtkCallback) (GtkWidget *widget, gpointer user_data);

Estruturas de instâncias devem ser declaradas usando `G_DECLARE_FINAL_TYPE` ou `G_DECLARE_DERIVABLE_TYPE`:

#define GTK_TYPE_FOO (gtk_foo_get_type ()) G_DECLARE_FINAL_TYPE (GtkFoo, gtk_foo, GTK, FOO, GtkWidget)

Para tipos finais, dados privados podem ser armazenados em um objeto `struct`, o qual deve ser definido no arquivo C:

struct _GtkFoo { GObject instancia_pai;

guint dados_privados; gpointer mais_dados_privados; };

Para tipos deriváveis, dados privados devem estar armazenados em um struct privado no arquivo C, configurado usando `G_DEFINE_TYPE_WITH_PRIVATE()` e acessado usando uma função `_get_instance_private()`:

#define GTK_TYPE_FOO gtk_foo_get_type () G_DECLARE_DERIVABLE_TYPE (GtkFoo, gtk_foo, GTK, FOO, GtkWidget)

struct _GtkFooClass { GtkWidgetClass parent_class;

void (* handle_frob) (GtkFrobber *frobber, guint n_frobs);

gpointer padding[12]; };

Sempre use as macros `G_DEFINE_TYPE()`, `G_DEFINE_TYPE_WITH_PRIVATE()` e `G_DEFINE_TYPE_WITH_CODE()` ou suas variantes abstratas `G_DEFINE_ABSTRACT_TYPE()`, `G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE()` e `G_DEFINE_ABSTRACT_TYPE_WITH_CODE()`; também, use as macros similares para definir interfaces e tipos “boxed”.

Tipos de interfaces devem sempre ter um typedef dummy visando as chamadas:

typedef struct _GtkFooable GtkFooable;

A estrutura da interface deve ter ‘Interface’ pós-fixado ao typedef dummy:

typedef struct _GtkFooableInterface GtkFooableInterface;

Interfaces devem ter as seguintes macros:

Macro | Expande para
--- | ---
`GTK_TYPE_iface_name` | `iface_name_get_type`
`GTK_iface_name` | `G_TYPE_CHECK_INSTANCE_CAST`
`GTK_IS_iface_name` | `G_TYPE_CHECK_INSTANCE_TYPE`
`GTK_iface_name_GET_IFACE` | `G_TYPE_INSTANCE_GET_INTERFACE`

# Alocação de memória

Quando se estiver alocando dados em uma pilha, use `g_new()`.

Tipos de estrutura pública devem sempre ser retornados após serem zerados, seja explicitamente para cada membro, seja usando `g_new0()`.

Veja para mais detalhes.

# Macros

Tente evitar macros privadas, a menos que seja estritamente necessário. Lembre-se de usar `#undef` nelas no final de um bloco ou uma série de funções que precisem delas.

Funções em linha são geralmente preferíveis a macros privadas.

Macros públicas não devem ser usadas a menos que elas sejam avaliadas para uma constante.

# API pública

Evite exportar variáveis como API pública, já que isso pode ser pesado demais para algumas plataformas. Em vez disso, é sempre preferível adicionar “gets” e “sets”. Também, cuidado com variáveis globais em geral.

# API privada

Funções não exportadas que são necessárias em mais de um arquivo fonte devem ser prefixadas com um sublinhado (‘_’) e declarados em um arquivo de cabeçalho privado. Por exemplo, `_minhalib_foo_interno()`.

Funções prefixadas com sublinhado nunca são exportadas.

Funções não exportadas que são necessárias apenas em um arquivo fonte devem ser declaradas com estáticas.