Pergunta

Eu estou trabalhando em um projeto em um 8051 onde cada byte contagem. Como tal, estou usando algumas variáveis ??globais onde eu normalmente não faria. O método normal de passar ponteiros para uma função adiciona muita sobrecarga aqui.

Eu tenho um número de funções que usam variáveis ??de um único bit (uma extensão do compilador específico para C ) para sinalizar o resultado de uma função, além do valor de retorno normal.

bit global_error_flag = 0;
bit global_data_ready_flag = 0;

unsigned char A_Function (void) {
    // Do some stuff

    if ( badness ) {
        global_error_flag = 0;
        global_data_ready_flag = 1;

        return 0;
    }

    if ( data_is_ready_use ) {
        global_data_ready_flag = 1;
    }

    return a_value;    
}

void Other_Function (void) {
    unsigned char c;

    c = A_Function();

    if( global_error_flag) {
        // Do error stuff here.
    }
    else
    if( global_data_ready_flag ) {
        // Do data processing here.
    }
    global_error_flag = 0;
    global_data_ready_flag = 0;

}

Uma vez que a técnica é mal, existe alguma maneira eu posso fazer o código mais claro?

Qual a melhor forma que eu deveria indicar quais as chamadas função terá o efeito colateral de definir essas bandeiras? São comentários suficiente? Devo citar as funções para indicar a sua API (quasi-estilo húngara)? Devo usar um macro para marcar essas chamadas:

#define FUNCTION_SETS_FLAGS(code) (code)

FUNCTION_SETS_FLAGS( c = A_Function() );

Quaisquer outras ideias?

Foi útil?

Solução

Seus globals são rotulados para maior clareza, que é um bom começo.

Idealmente você quer algo que não irá compilar se você errar. Isso significa macros e comentários não vai funcionar.

Eu furar a uma convenção de nomenclatura para as funções -. Não necessariamente húngaro, mas algo como A_Function_Returns_Flags ou menos detalhada se você pode pensar que

Outras dicas

Usando uma convenção, se você quiser chamá-lo "Hungarian" ou não, é a melhor maneira que eu posso pensar para marcar este improviso. Estilisticamente, algum tipo de nomear prefixo seria preferível sobre o #define vazio, pelo menos para mim.

Este é realmente muito comum, eu acho. Eu sei que o ambiente de programação S60 usa um monte de marcas convencionais sobre as funções para indicar que eles lançar exceções, por exemplo.

Eu fiz o meu Ph.D. sobre um problema semelhante no Java. Posso dizer-lhe uma coisa que você não deve fazer: não contam com a documentação porque então você depende de alguém realmente lê-lo. Você precisa adicionar algum indício no nome do método para indicar que o usuário deve ler a documentação para aprender sobre os efeitos colaterais. Se você pegar alguma coisa e são consistentes com ele, você provavelmente ficar o mais oportunidade.

Se você quiser apenas para mencionar que uma função afeta variável global (s), então um simples (húngaro) prefixo pode ajudar.

Mas se você quiser mencionar cada bandeira única (s) que afeta, em seguida, usando o cabeçalho da função é provavelmente o caminho a percorrer. Como por exemplo,

  /*************************************************************************
     * FUNCTION    : <function_name>
     * DESCRIPTION : <function description> 
     * PARAMETERS  : 
     *  Param1  - <Parameter-1 explanation>
     *  Param2  - <Parameter-2 explanation>
     *  Param3  - <Parameter-3 explanation>
     * RETURN      : <Return value and type>
     * GLOBAL VARIABLES USED: 
     *  Global1 - <Global-1 explanation>
     *  Global2 - <Global-2 explanation>
     *  Global3 - <Global-3 explanation> 
  *************************************************************************/

Isto não realmente ajudá-lo, mas GCC tem uma maneira de fazer o oposto do que você quer: a funções de marca que têm não efeitos colaterais. Veja a const atributos pure . Isto é mais para a otimização de documentação, pensei: se o compilador sabe que uma determinada função não examinar quaisquer outros do que os seus argumentos dados, ele pode realizar otimizações mais inteligentes, como loop-invariante movimento código .

Você pode usar uma macro para simular a função para ter mais parâmetros:


unsigned char _a_function(void);

#define A_Function(ret_val) (*(ret_val) = _a_function(), !global_error_flag)

...
unsigned char var;
/* call the function */
if (!A_Function(&var))
{
    /* error! */
}
else
{
    /* use var */
    var++;
}

Eu não tentei para compilá-lo, por isso não posso dizer que isso vai funcionar, mas eu acho que deveria.

Em primeiro lugar eu tentaria código lo de uma forma que há apenas um produtor e apenas um consumidor de cada uma dessas bandeiras. Então eu iria limpar / definir um sinalizador somente quando necessário. Tal como para indicar o efeito colateral, um cabeçalho padrão no topo da função, estilo doxygen, deve ser suficiente:

    // Function func
    // Does something
    // Consumes ready_flag and  sets error_flag on error.

    int func()
    {
        if (ready_flag)
        {
            //do something then clear the flag
            if (some_error)
                error_flag = x;
            ready_flag = 0;
        }
        //don't mess with the flags outside of their 'scope'
        return 0;
    }

Por outro lado, se as bandeiras de erro e prontos são mutuamente exclusivos, você poderia usar um byte (ou bits dentro de um byte / registo) para indicar a prontidão ou um estado de erro.

0 para um erro, um para não-pronto / livre de erros e 2 para pronto / livre de erros (ou -1, 0, 1, qualquer que seja)

IIRC, o conjunto de 8051 instrução padrão não funcionar em pedaços individuais, portanto, usando um byte inteiro para (diversos) bandeiras não deve dar-lhe um desempenho enorme sucesso.

Se você não tiver feito isso, você pode também querer verificar o href="http://sdcc.sourceforge.net" rel="nofollow projeto sdcc no SourceForge , é um compilador C especificamente concebido para ser utilizado para desenvolvimento de sistemas embarcados que também tem como alvo a 8051, além do compilador suporta um número de costume, específica do destino e intrínsecos do compilador não-padrão para vários casos de uso, também eu pessoalmente tenho encontrado o desenvolvimento equipe para ser muito aberto e sensível sobre idéias para novas melhorias e outros pedidos de recurso relacionado.

Se você realmente tem que ficar com estas variáveis ??globais, você pode torná-lo óbvio que uma função pode modificá-los, esperando que referências a eles como argumentos de função:

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag)
{
  ...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top