Diretrizes de codificação
Estilo de codificação CNTK
Esta página documenta as convenções utilizadas no código fonte de CNTK. Por favor, adiem estas convenções ao escrever um novo código. Siga o senso comum e rompa funções que excedam um limite razoável (algumas páginas de ecrã), use nomes significativos, comente bem e mantenha comentários e código sincronizados, etc.
Básico: entalhe, espaçamento e aparelho
O código é consistentemente recuado usando quatro espaços. Os caracteres do separador não são permitidos em nenhum lugar do código. As únicas exceções são Makefiles, outro sistema de construção ou ficheiros de dados onde os caracteres do separador são sintactamente necessários.
Os seguintes blocos de código são recortados:
- Corpos de declarações de controlo: para, se, enquanto, trocar, etc.
- Blocos de declaração gratuitos, ou seja, chaves de abertura e fecho que não seguem qualquer declaração de controlo. Estas são às vezes usadas para limitar a vida útil dos objetos.
- Corpos de classes e funções.
- As declarações continuaram da linha anterior.
- Código no caso de as declarações começarem na linha após a declaração do caso e são recortadas.
As seguintes coisas não são recoradas:
- Conteúdo de espaços de nome.
- Etiquetas de caso
- Especificadores de controlo de acesso.
As declarações de funções com listas de parâmetros longos podem ser divididas em várias linhas. A declaração de parâmetros sobre as linhas divididas deve ser recorrida à parêntese de abertura da declaração de funções. As chamadas para funções com longas listas de parâmetros podem ser divididas em várias linhas, as linhas divididas devem ser recortadas para o parênteses de abertura da declaração de função associada.
O código é escrito utilizando aparelhos estilo Allman ou BSD Unix. Este estilo coloca a braçadeira associada a uma declaração de controlo na linha seguinte, recuada ao mesmo nível da declaração de controlo. As declarações dentro dos aparelhos são recuadas para o nível seguinte, recomenda-se nunca omitir aparelhos, mesmo para pequenos blocos.
Os espaços estão presentes nos seguintes locais:
- Em torno de todos os operadores binários, incluindo atribuições
- Entre uma palavra-chave e parênteses
- Entre um identificador ou palavra-chave e uma cinta
- Depois de vírgulas e semi-acolchos que não terminam uma linha
Os espaços estão ausentes nos seguintes locais:
- Antes de escotínios e vírgulas
- No lado interno dos parênteses
- Entre um nome de função e a sua lista de argumentos
- Entre operadores nãoários e seus operáticos
- Dentro de uma lista de argumentos vazios
- Entre um rótulo e um cólon
- Em torno do operador de âmbito ::
As listas de inicializadores de membros e as listas de classes base que contenham mais de uma classe devem ser escritas numa linha separada. Isto torna muito fácil detetar erros.
namespace Microsoft { namespace MSR { namespace CNTK {
Matrix ImplodeSelf(int x);
int ConfuseUs(float y);
class MainPart:
public Head,
protected Heart
{
public:
MainPart():
m_weight(99),
m_height(180)
{}
private:
void EatMore();
int m_consume, m_repeater;
};
template <typename Box>
void Inspect(Box & container)
{
switch (container)
{
case 1:
PrepareIt();
break;
case 2:
Finish();
break;
default:
break;
}
for (int i = 0; i < 30; ++i)
{
container << EatMore();
}
return container;
}
} } }
Convenções de nomenclatura
- Os nomes de classe e espaço de nome usam UpperCamelCase aka PascalCase.
- Nomes geralmente escritos em all-caps (SQL, CNTK, ...) podem permanecer em todos os casos superiores.
- Funções estáticas globais e públicas, variáveis de pilha e membros de classe (variáveis de classe) usam o LowerCamelCase.
- As funções dos membros da classe (métodos) utilizam o UpperCamelCase.
- Macros e constantes usam UPPER_SNAKE_CASE.
- Os parâmetros do modelo que são os tipos usam UpperCamelCase.
- Os prefixos do tipo, a notação húngara, etc. são proibidos. Utilize sufixos significativos se precisar de desambiguar, por exemplo, floatMatrix e NormalizedDoubleMatrix.
Prefixos de nome
m_
para variáveis membros_
para variáveis estáticas em qualquer contextog_
para as variáveis globais, que devem ser evitadas em primeiro lugar (tanto quanto possível)
Nomes variáveis devem ser substantivos. Os nomes das funções devem ser verbos, com exceção dos getters, que podem ser substantivos. Por exemplo, uma propriedade de classe chamada posição teria o setPosition setter() e a posição getter().
Convenções de nome de arquivo
Os ficheiros C++ devem ter a extensão .cpp, enquanto os ficheiros do cabeçalho devem ter a extensão .h. Não são permitidos espaços e sublinhados. A utilização de números em ficheiros é desencorajada.
#define GOOD_MACRO(x) x
void CallOut();
unsigned const g_theAnswer = 42;
class SolveAllProblems
{
public:
void DoWhatWeNeed();
static void SetBugsOff();
int m_countReasons;
protected:
void NeverWorking();
static void GetReason();
int internalCounter;
private:
void InternalNeeds();
static void ShowReason();
int m_countShows;
};
template <typename TypeParam, int numberOfReasons>
void CallGlobal(boost::array<TypeParam, numberOfReasons> const &array);
Pré-processamento
A compilação condicional utilizando o pré-processo é fortemente desencorajada, uma vez que leva à podridão do código. Utilize-o apenas quando for inevitável, por exemplo, quando é utilizada uma dependência opcional. Um caso especial está a usar a compilação condicional para excluir um ficheiro inteiro baseado na plataforma, o que é permitido.
Em preferência ao código condicionalmente compilado e específico da plataforma, deverá ter como objetivo escrever código portátil que funcione da mesma forma independentemente da plataforma. A utilização das bibliotecas Boost pode ajudar muito neste aspeto. Se tiver de utilizar códigos diferentes dependendo da plataforma, tente englobá-lo em funções de ajudante, de modo a que a quantidade de código que difere entre as plataformas seja mantida ao mínimo.