2012-01-02 38 views
5

Ok, esto puede sonar un poco vago por el título, pero eso es porque no tengo idea de cómo redactarlo de otra manera. Trataré de explicar lo que quiero decir: muy a menudo en ciertas bibliotecas, la función 'init' acepta algunos parámetros, pero ese parámetro luego acepta múltiples parámetros (derecha ..). Un ejemplo, sería así:Parámetros múltiples en un único parámetro (funciones) en C/C++

apiHeader.h

#define API_FULLSCREEN 0x10003003 
#define API_NO_DELAY  0x10003004 
#define API_BLAH_BLAH 0x10003005 

main.c:

apiInit(0, 10, 10, 2, API_FULLSCREEN | API_NO_DELAY | API_BLAH_BLAH); 

¿Cómo funciona esto? No puedo encontrar la respuesta en ningún lado, probablemente porque no sé cómo se llama, así que no tengo ni idea de qué buscar. Sería muy útil en mi proyecto actual.

¡Gracias de antemano!

+2

Como lo ha escrito, que ganó ** 't ** trabajo, porque tus banderas no están configurando diferentes bits. –

+0

Esto es me doy cuenta, era principalmente para propósitos de ejemplo. Perdóname, ¡no he dormido en 30 horas! :( –

Respuesta

5

Este quinto parámetro suele ser una máscara. Funciona mediante la definición de varios consts (probablemente un enum) con valores que son potencias de dos o combinaciones de ellos. Luego se codifican en un solo valor usando |, y se decodifican usando &. Ejemplo:

#define COLOUR_RED 0x01 
#define COLOUR_GREEN 0x02 
#define COLOUR_BLUE 0x04 
#define COLOUR_CYAN (COLOUR_BLUE | COLOUR_GREEN) // 0x06 

// Encoding 
SetColour(COLOUR_RED | COLOUR_BLUE); // Parameter is 0x05 

// Decoding 
void SetColour(int colour) 
{ 
    if (colour & COLOUR_RED) // If the mask contains COLOUR_RED 
    // Do whatever 
    if (colour & COLOUR_BLUE) // If the mask contains COLOUR_BLUE 
    // Do whatever 
    // .. 
} 
+0

Esto es exactamente lo que necesitaba saber. Muchas gracias, me sentí algo así, ¡pero no pude encontrar un ejemplo en el código fuente que busqué! –

+0

De nada. – Gorpik

9

El parámetro se suele llamar "flags $ FOO" y los valores son or -ed. El punto es que el parámetro es un tipo numérico que se construye como el bit or de múltiples valores posibles.

En las funciones de tratamiento, los valores se probado por lo general con un bit a bit and:

if ((flags & API_FULLSCREEN) != 0) 

usted tiene que ser cuidadosa para asignar valores de una manera que mantiene la o lineal operación. En otras palabras, no configure el mismo bit en dos valores diferentes or -able, como lo hizo en su encabezado. Por ejemplo,

#define API_FULLSCREEN 0x1 
#define API_NO_DELAY  0x2 
#define API_BLAH_BLAH 0x4 

obras y le permite deconstruir todas las combinaciones de banderas en su función, pero

#define API_FULLSCREEN 0x1 
#define API_NO_DELAY  0x2 
#define API_BLAH_BLAH 0x3 

no porque API_FULLSCREEN | API_NO_DELAY == API_BLAH_BLAH.

Viendo desde un nivel superior, a flags int es la lista de argumentos variables de un hombre pobre. Si considera C++, debe encapsular tal detalle en una clase o al menos un std::bitset.

+0

Preferiblemente trabajo en C, así que supongo que esta es la forma en que tendré que buscarlo por ahora. Sin embargo, echaré un vistazo a std :: bitset, ya que es bueno saber esas cosas que haría Asumir. Tu respuesta fue muy esclarecedora, ¡gracias! –

+0

Decidí marcar la otra pregunta como respuesta, ya que proporcionó un ejemplo más tangible. Realmente quiero marcar ambas respuestas, así que solo quería agradecerte de nuevo. :) –

+0

Su ejemplo bit a bit es incorrecto. La precedencia del operador significa que necesita paréntesis para obtener el resultado deseado: 'if ((flags & API_FULLSCREEN)! = 0)'. – ChrisN

1

Lo que están haciendo allí es usar el binario OR para combinar las banderas.

así que lo que está sucediendo realmente es:

0x10003003 | 0x10003004 | 0x10003005 == 0x10003007

Es todavía un parámetro, pero las 3 banderas se combinan para crear un valor único para ese parámetro que se puede utilizar en la función.

+0

Pensé que sería algo así, pero se me ocurren varias cosas. Por ejemplo, ¿qué pasa si el resultado de dos banderas sería el mismo? ¿Podrías dar un ejemplo práctico rápido y sucio de cómo funciona esto? Tendría que ir primero a calcular -cada posibilidad- y luego hacer un cambio (indicadores) {/ * casos van aquí * /} –

+0

@JesseBrands El programador debería asegurarse de que no haya valores idénticos. Entonces, sí, tendría que hacer un cambio con los valores de indicador precalculados. – Serdalis

+1

@JesseBrands: las banderas deben ser ortogonales, por supuesto. Para un vector de bits, esto significa que cada indicador establece exactamente un bit específico (y tal vez un bit de máscara no ortogonal para indicar que se ha utilizado uno de un grupo de indicadores). – datenwolf

1

Lo que está definiendo como parámetro múltiple es estrictamente un único parámetro desde el punto de vista de la firma de la función. En cuanto al manejo de múltiples Options basado en un solo parámetro, como puede ver, está el bitwise Or Operator que establece un valor único para el valor del parámetro. El cuerpo de la función utiliza bits individuales para determinar la configuración completa.

Normalmente, se asigna un bit para una opción y generalmente tienen dos valores de estado (verdadero/falso).

0

OR bit a bit

OR bit a bit funciona casi de la misma manera como AND bit a bit. La única diferencia es que solo uno de los dos bits debe ser un 1 para el bit de esa posición en el resultado para ser 1. (Si ambos bits son un 1, el resultado también tendrá un 1 en esa posición). El símbolo es un tubo: |. De nuevo, esto es similar al operador lógico booleano, que es ||.

01001000 | 10111000 = 11111000

y en consecuencia 72 | 184 = 248

Por lo tanto, en su método no es un parámetro múltiple, en realidad es un parámetro. puede usar la operación de Bitwise OR en API_FULLSCREEN | API_NO_DELAY | API_BLAH_BLAH y lo pasó en el método.

0

El ejemplo que proporcionó no funcionará como se esperaba. Lo que se hace es utilizar un poco particular para una opción en particular - y el O combina entonces

Ejemplo

#define OPT1 1 
#define OPT2 2 
#define OPT3 4 

Así bit 1 es para OPT1, bit 2 es para OPT2 etc.

Así

OPT1 | OPT3 activa el bit 1 y 3, y da un valor de 5

En la función se puede comprobar si se requiere una opción en particular mediante el y ópera tor

Así

void perform(int opts) 
{ 
if (opts & OPT1) 
{ 
// Do stuff for OPT1 
} 
... 
1

El parámetro se denomina habitualmente "banderas" y contiene una combinación o-ed de un conjunto de valores permitidos.

int flags = API_FULLSCREEN | API_NO_DELAY; 

La función se la tome este parámetro entero y extraer los elementos individuales de esta manera:

int fullscreen_set = flags & API_FULLSCREEN; 
int no_delay_set = flags & API_NO_DELAY; 
int blah_blah_set = flags & API_BLAH_BLAH; 

Para que esto funcione hay que ser carfull en la forma en que uno elige los valores numéricos para la API_ * parámetros.

0

El valor de estos parámetros se define de forma que no tengan ninguna superposición.Algo como esto:

#define A 0x01 
#define B 0x02 
#define C 0x04 
#define D 0x08 

Teniendo en cuenta las definiciones anteriores, el siempre se puede determinar cuál de las variables anteriores han sido OR ed usando el operador de bits AND:

void foo(int param) 
{ 
    if(param & A) 
    { 
     // then you know that A has been included in the param 
    } 
    if(param & B) 
    { 
     // then you know that B has been included in the param 
    } 
    ...  
} 

int main() 
{ 
    foo (A | C); 
    return 0; 
} 
Cuestiones relacionadas