Compartilhar via


Codificando diretrizes

estilo de codificação CNTK

Esta página documenta as convenções usadas no código-fonte do CNTK. Adere a essas convenções ao escrever um novo código. Siga o senso comum e divida funções que excedem um limite razoável (algumas páginas de tela), use nomes significativos, comente bem e mantenha comentários e código em sincronia, etc.

Noções básicas: recuo, espaçamento e chaves

O código é consistentemente recuado usando quatro espaços. Caracteres tab não são permitidos em nenhum lugar no código. As únicas exceções são Makefiles, outro sistema de build ou arquivos de dados em que os caracteres de tabulação são necessários de forma sintática.

Os seguintes blocos de código são recuados:

  • Corpos de instruções de controle: para, se, enquanto, alternar, etc.
  • Blocos de instrução gratuita, ou seja, chaves de abertura e fechamento que não seguem nenhuma instrução de controle. Às vezes, eles são usados para limitar o tempo de vida dos objetos.
  • Corpos de classes e funções.
  • As instruções continuaram da linha anterior.
  • As instruções de código no caso começam na linha seguindo a instrução case e são recuadas.

As seguintes coisas não são recuadas:

  • Conteúdo de namespaces.
  • Rótulos case
  • Especificadores de controle de acesso.

As declarações de função com listas de parâmetros longas podem ser divididas em várias linhas. A declaração de parâmetro nas linhas divididas deve ser recuada para o parêntese de abertura da declaração de função. Chamadas para funções com listas de parâmetros longas podem ser divididas em várias linhas, as linhas divididas devem ser recuadas para o parêntese de abertura da instrução de função associada.

O código é escrito usando chaves de estilo Allman ou BSD Unix. Esse estilo coloca a chave associada a uma instrução de controle na próxima linha, recuada para o mesmo nível que a instrução de controle. As instruções dentro das chaves são recuadas para o próximo nível, é recomendável nunca omitir chaves, mesmo para blocos pequenos.

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 uma palavra-chave e uma chave
  • Após vírgulas e ponto e vírgula que não terminam uma linha

Os espaços estão ausentes nos seguintes locais:

  • Antes de ponto e vírgula e vírgulas
  • No lado interno dos parênteses
  • Entre um nome de função e sua lista de argumentos
  • Entre operadores unários e seus operandos
  • Dentro de uma lista de argumentos vazia
  • Entre um rótulo e dois-pontos
  • Ao redor do operador de escopo ::

Listas de inicializadores de membro e listas de classes base que contêm mais de uma classe devem ser gravadas em uma linha separada. Isso torna muito fácil detectar 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

  • Nomes de classe e namespace usam UpperCamelCase também conhecido como PascalCase.
  • Os nomes comumente escritos em todas as tampas (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 lowerCamelCase.
  • As funções de membro de classe (métodos) usam UpperCamelCase.
  • Macros e constantes usam UPPER_SNAKE_CASE.
  • Parâmetros de modelo que são tipos usam UpperCamelCase.
  • Prefixos de tipo, notação húngara etc. não são permitidos. Use sufixos significativos se precisar desambiguar, por exemplo, floatMatrix e normalizedDoubleMatrix.

Prefixos de nome

  • m_ para variáveis de membro
  • s_ para variáveis estáticas em qualquer contexto
  • g_ para variáveis globais, que devem ser evitadas em primeiro lugar (tanto quanto possível)

Nomes de variáveis devem ser substantivos. Os nomes de função devem ser verbos, com exceção de getters, que podem ser substantivos. Por exemplo, uma propriedade de classe chamada posição teria o setter SetPosition() e o getter Position().

Convenções de nome de arquivo

Os arquivos C++ devem ter a extensão .cpp, enquanto os arquivos de cabeçalho devem ter a extensão .h. Espaços e sublinhados não são permitidos. O uso de números em nomes de arquivo é desencorajado.

#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é-processador

A compilação condicional usando o pré-processador é fortemente desencorajada, pois leva à roteamento de código. Use-o somente quando for inevitável, por exemplo, quando uma dependência opcional for usada. Um caso especial está usando a compilação condicional para excluir um arquivo inteiro com base na plataforma, o que é permitido.

Em preferência ao código condicionalmente compilado, específico da plataforma, você deve ter como objetivo escrever um código portátil que funcione da mesma forma, independentemente da plataforma. Usar as bibliotecas boost pode ajudar muito nesse aspecto. Se você precisar usar um código diferente dependendo da plataforma, tente encapsulá-lo em funções auxiliares, para que a quantidade de código que difere entre plataformas seja mantida no mínimo.