2010-06-30 16 views
6

¿cuál de estos dos es mejor?devuelve un int o pasa un puntero int - ¿Qué es mejor?

void SetBit(int *flag, int bit) 
{ 
    *flag |= 1 << bit; 
} 

O

int SetBit(int flag, int bit) 
{ 
    flag |= 1 << bit; 
    return flag; 
} 
+1

Personalmente, siento que lo mejor es utilizar todo el int (o carbón o corto o lo que sea) como la bandera booleana. Claro que usa más memoria, pero es mucho más legible. A menos que la memoria sea una restricción seria, evite los trucos cuando sea posible. – corsiKa

+0

¿por qué los votos hacia abajo? – Polaris878

+0

@Polaris: Mi conjetura sería que la gente pensaba que era una cuestión de rendimiento (casi me downvoted por eso antes de volver a leer un par de veces ...) –

Respuesta

7

me gusta el segundo, ya que no tiene efectos secundarios. Si desea modificar flag, sólo tiene que asignar el resultado a sí mismo:

flag = SetBit(flag, 4); 
6

Ni.

int SetBit(int flag, int bit) 
{ 
    return flag | 1 << bit; 
} 
+0

Definitivamente esto. No cave en una variable de parámetro si no tiene una buena razón para hacerlo. Devuelve el valor modificado y permite al usuario volver a asignarlo a la variable si lo desea. –

+5

¿No crees que el compilador podría optimizar eso de todos modos? –

+0

@Platinum: No es una cuestión de rendimiento, es una cosa de legibilidad. –

1

me gusta el segundo mejor ...

Sin embargo, me recomiendan cambiar el nombre de su función para ser más descriptivo (suponiendo que esto es el nombre real). "SetBit" no hace mucho para describir lo que hace la función o lo devuelve :)

+0

¿No es así? Parece tener sentido para mí: establece el bit en la variable de indicador dada. –

+1

En realidad, no estoy de acuerdo: la función se establece un poco. La función podría usarse en cualquier contexto donde deba establecerse un bit. – corsiKa

+0

Establece "el bit" a qué? – Polaris878

5

Depende.

El primero es el estilo imperativo, el segundo es el estilo funcional.

Si quieren hacer

SetBit(SetBit(... SetBit(flag, b1), b2),...), bn) 

hacer el segundo. Si desea

SetBit(&flag, b1) 
SetBit(&flag, b2) 
... 
SetBit(&flag, bn) 

hacer el primero. En C, preferiría lo último (es decir, el imperativo). En otros idiomas/contextos, el primero puede ser una buena idea.

+0

Un mal uso del estilo funcional (funciones de anidamiento profundo) no es una excusa para evitarlo. Si desea enumerarlos todos en líneas separadas, puede asignar el resultado de SetBit a la variable de indicador en cada línea. –

+0

¿Realmente recomendaría realmente usar ese primer patrón en C alguna vez? (No voto negativo, pero tengo que cuestionar tu mención porque todo será casi ilegible!) –

+0

@Platinum No estoy seguro, pero no puedo pensar en una buena e inmediata justificación para la construcción funcional aquí. –

1

Depende.

En ese caso, de cualquier manera funcionaría realmente. Pero puedo pensar en dos casos especiales en los que preferiría usar un puntero.

  1. Si el tipo que está pasando es grande y una copia de valor sería costosa, use un puntero por motivos de rendimiento.

  2. Si necesita devolver algo más, tal vez un código de estado o indicación de éxito/fracaso, entonces es necesario utilizar el puntero para que pueda dejar espacio para devolver el valor que necesita para volver.

personalmente creo que fuera de esas situaciones, la segunda (pasa/retorno por valor) es más claro y ligeramente más legible.

1

El segundo es mejor porque no se bloqueará.

La primera de ellas se podría bloquearse si se pasa en un puntero no válido NULL por lo que tendría que tener algún código para revisar y manejar eso.

0

Pase un int para ahorrar tiempo desreferenciando el puntero.

+0

De todos modos, esta función va a estar enlistada por cualquier compilador razonable. - No me preocuparía el rendimiento aquí. –

+0

Especialmente en el mundo de sistemas integrados, no todos los compiladores alinearán tales cosas. Además, el patrón surge en muchos casos donde el código es suficientemente complejo como para que no sea práctico. Según mi interpretación, la pregunta no era sobre cómo debería establecer bits en una variable, sino sobre qué patrón de codificación era mejor. – supercat

5

me gustaría utilizar una macro:

#define BIT_SET(a, bit) ((a) | (1 << (bit))) 
+2

Por qué no, pero aún así lo llamaría SET_BIT;) –

+3

+1 Yo usaría también una macro –

+2

+1 Definitivamente una macro (una llamada a función es costosa en tales casos) – INS

5

Para ser honesto, creo que esto sólo anima a la gente a usar "números mágicos" como banderas:

SetBit(&flags, 12); // 12 is the flag for Super mode 

lo que realmente quiere es nombrado constantes :

#define SUPERMODE_FLAG 12 
... 
SetBit(&flags, SUPERMODE_FLAG); 

Pero si va a usar constantes con nombre, también podría nombrar máscaras en lugar de bit nu mbers, en cuyo caso la operación es tan simple que no hay necesidad de una función auxiliar:

#define SUPERMODE_MASK (1 << 12) 
.... 
flags |= SUPERMODE_MASK; 

En el caso inusual de que está manipulando bits individuales por número, sin saber lo que significan, entonces yo prefiero la segunda por la misma razón que Kristo: encuentro que las funciones libres de efectos secundarios son un poco más fáciles de razonar que los mutadores.

0

En primer lugar está bien si las funciones que va a ser inline. Sin subrayar, eso es demasiada sobrecarga para pasar los punteros a los enteros. (En arcos de 64 bits LP64, int es de 4 bytes, es puntero 8.)

Segundo ... SETBIT nombre de la función() va a causar cierta confusión leve. El nombre implica que la función cambia algo, mientras que de hecho no lo hace. Siempre que esté de acuerdo con el nombre, entonces es una mejor opción en términos de rendimiento.

E.g. El kernel de Linux utiliza para muchas cosas similares la variante del puntero, ya que a menudo la ubicación de la memoria del dato es importante o necesaria para la portabilidad. Pero o bien hacen de todas esas funciones una macro de preprocesador o marcan con el atributo always_inline de gcc. Para la programación simple de la aplicación, diría que la segunda debería ser la preferida. Solo elige un nombre mejor.

0

Si el único patrón para utilizar la función será "variable = doSomething (variable);" y el rendimiento no es un problema, consideraría "hacer algo" (variable &); " para ser más legible El único momento en el que preferiría lo primero sería si el destino fuera a veces algo distinto de la fuente, o si el rendimiento fuera crucial y el compilador de uno no pudiera manejar eficientemente el último caso (común en los sistemas integrados).

Cabe señalar que este último formato permite que algo de lo primero no lo hace. En VB-style:

 
Sub OrBits(ByRef N as Integer, ByVal Bits as Integer) 
    Dim OldValue as Integer 
    Do 
    OldValue = N 
    Loop While Threading.Interlocked.CompareExchange(N, OldValue or Bits, OldValue) <> OldValue 
End Sub 

El efecto de este código será siempre la de O los bits especificados en N, aunque algo más cambia N mientras que la función está en marcha. No es posible lograr ese comportamiento con la estrategia de lectura y devolución.

Cuestiones relacionadas