Pregunta

Estoy trabajando en un proyecto en un 8051 donde cada byte cuenta.Como tal, estoy usando algunas variables globales que normalmente no usaría.El método normal de pasar punteros a una función añade demasiada sobrecarga aquí.

Tengo una serie de funciones que utilizan variables de un solo bit (una extensión específica del compilador para C) para señalar el resultado de una función además del 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;

}

Dado que la técnica es mala, ¿hay alguna manera de aclarar el código?

¿Cuál es la mejor manera de indicar qué llamadas a funciones tendrán el efecto secundario de configurar estos indicadores?¿Son suficientes los comentarios?¿Debo nombrar las funciones para indicar su API (estilo casi húngaro)?¿Debo usar una macro para marcar este tipo de llamadas?

#define FUNCTION_SETS_FLAGS(code) (code)

FUNCTION_SETS_FLAGS( c = A_Function() );

¿Alguna otra idea?

¿Fue útil?

Solución

Sus globales están etiquetados para mayor claridad, eso es un buen comienzo.

Lo ideal sería que usted quiere algo que no se compilará si uno se equivoca. Eso significa que las macros y los comentarios no funcionarán.

Me gustaría poner una convención de nomenclatura para las funciones - no necesariamente húngaros, sino algo así como A_Function_Returns_Flags o menos detallado si se puede pensar en que

.

Otros consejos

El uso de una convención, si quiere llamarlo "Húngara" o no, es la mejor manera que puedo pensar para marcar este brusco. Estilísticamente, algún tipo de nombrar el prefijo sería preferible a la #define vacío, al menos para mí.

Esto es en realidad bastante común, creo. Yo sé que el entorno de programación S60 utiliza una gran cantidad de marcas convencionales en funciones para indicar que generan excepciones, por ejemplo.

Hice mi doctorado en un problema similar en Java. Te puedo decir una cosa que no debe hacer: no se basan en la documentación porque entonces dependes de alguien realmente leerlo. Es necesario añadir un poco de toque en el nombre de método para indicar que el usuario debe leer la documentación para aprender acerca de los efectos secundarios. Si tienes que elegir algo y en consonancia con él, es probable que destacan la mayoría de la ocasión.

Si lo que desea es mencionar que afecta a una función variable global (s), entonces un simple (húngaro) prefijo podría ayudar.

Pero si quieres hablar de todas las banderas (s) única que afecta, a continuación, utilizando la cabecera de la función es probablemente el camino a seguir. Como por ejemplo,

  /*************************************************************************
     * 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> 
  *************************************************************************/

Esto realmente no te ayuda, pero GCC tiene una manera de hacer el opuesto de lo que quieres:para marcar funciones que tienen No efectos secundarios.Ver el const y pure atributos.Esto es más para optimización que para documentación, pensé:Si el compilador sabe que una función determinada no examina ningún dato que no sean sus argumentos, puede realizar optimizaciones más inteligentes, como movimiento de código invariante en bucle.

Se puede usar un macro para simular la función de tener más 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++;
}

No he tratado de compilar, así que no puedo decir que esto va a funcionar, pero creo que debería.

En primer lugar me gustaría tratar de codificar de una manera que sólo hay un productor y sólo uno de los consumidores de cada una de esas banderas. Entonces me gustaría borrar / establecer un indicador sólo cuando sea necesario. En cuanto a lo que indica el efecto secundario, una cabecera estándar en la parte superior de la función, el estilo de doxygen, debe ser lo suficientemente:

    // 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 otro lado, si los indicadores de error y listos son mutuamente excluyentes, se puede utilizar un byte (o bits dentro de un byte / registro) para indicar la disposición o un estado de error.

0 para un error, 1 para no preparado / libre de errores y 2 para listo / libre de errores (o -1, 0, 1, cualquiera que sea)

IIRC, el conjunto de instrucciones estándar de 8051 no opera sobre los bits individuales, por lo que el uso de un byte conjunto de banderas (varios) no debe darle un enorme impacto en el rendimiento.

Si no lo ha hecho, es posible que también desee comprobar a cabo el proyecto sdcc en sourceforge , es un compilador de C específicamente destinado a ser utilizado para el desarrollo integrado, destinado también a la 8051, además del compilador soporta una serie de costumbre, los intrínsecos del compilador específicos de la diana y no estándar para diferentes casos de uso, también he encontrado personalmente el desarrollo equipo sea muy abierto y receptivo a las ideas para nuevas mejoras y otras peticiones relacionadas.

Si realmente tiene que pegarse con estas variables globales, puede que sea obvio que una función puede modificarlos esperando que las referencias a ellos como argumentos de la función:

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag)
{
  ...
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top