OVH Cloud OVH Cloud

Combinaison de propriétés

7 réponses
Avatar
Michael
Bonjour à tous,

désolé pour le titre un peu foireux, mais je ne sais pas comment qualifier
mon problème...

Je dois utiliser la fonction suivante, tirée d'une API:

HRESULT GetCaps (
IPin *pPin,
long *pCapsFlags
);

En voici la doc:

Parameters :

pCapsFlags
[out] Pointer to a value representing a combination of the flags from the
VideoControlFlags enumeration.

et voici VideoControlFlags:

typedef enum tagVideoControlFlags
{
VideoControlFlag_FlipHorizontal = 0x0001,
VideoControlFlag_FlipVertical = 0x0002,
VideoControlFlag_ExternalTriggerEnable = 0x0004,
VideoControlFlag_Trigger = 0x0008
} VideoControlFlags;

Donc pCapsFlags contient la liste des possibilités utilisables parmi
VideoControlFlags.

Mais comment je peux "extraire" la liste des possibilités?

Par exemple, comment je dois faire pour savoir si pCapsFlags contient
VideoControlFlag_FlipHorizontal?

J'imagine que ça doit être tout con (à base de << je pense) mais j'y arrive
pas...

Question liée:

Il faudra que j'utilise une fonction SetMode
HRESULT SetMode (
IPin *pPin,
long Mode
);

et donner à Mode la liste des possibilités... Donc l'inverse de la première
question, comment créer un long Mode contenant par exemple
VideoControlFlag_FlipVertical et VideoControlFlag_Trigger?

Un petit coup de main?

Merci d'avance...

7 réponses

Avatar
Sylvain
Michael wrote on 01/11/2006 15:50:

HRESULT GetCaps (IPin *pPin, long *pCapsFlags);

pCapsFlags
[out] Pointer to a value representing a combination of the flags from the
VideoControlFlags enumeration.

typedef enum tagVideoControlFlags
{
VideoControlFlag_FlipHorizontal = 0x0001,
VideoControlFlag_FlipVertical = 0x0002,
VideoControlFlag_ExternalTriggerEnable = 0x0004,
VideoControlFlag_Trigger = 0x0008
} VideoControlFlags;

Mais comment je peux "extraire" la liste des possibilités?


IPin* pin; une interface valide
long capsFlags;

if (GetCaps(pin, &capsFlags) == S_OK){
if ((capsFlags & 1) == 1) { le flip horizontal est supporté }
if ((capsFlags & 2) == 2) { le flip vertical est supporté }
if ((capsFlags & 4) == 4) { le trigger externe est supporté }
if ((capsFlags & 8) == 8) { le trigger est supporté }
}

bcp de fonctions fonctionnent ainsi un renseignant un entier selon "une
matrice de bits de configuration" ... c'est pas bien sorcier.

Sylvain.

Avatar
Michael
if (GetCaps(pin, &capsFlags) == S_OK){
if ((capsFlags & 1) == 1) { le flip horizontal est supporté }
if ((capsFlags & 2) == 2) { le flip vertical est supporté }
if ((capsFlags & 4) == 4) { le trigger externe est supporté }
if ((capsFlags & 8) == 8) { le trigger est supporté }
}

bcp de fonctions fonctionnent ainsi un renseignant un entier selon "une
matrice de bits de configuration" ... c'est pas bien sorcier.


Pas bien sorcier effectivement, mais je savais pas comment faire :)

Merci

Avatar
Sylvain
Michael wrote on 01/11/2006 16:31:

Pas bien sorcier effectivement, mais je savais pas comment faire :)



y'a pas de mal à apprendre ;)

<mode débutant (et ce n'est pas péjoratif)>

si de tels opérations au niveau bit (positionnement, test positionné ou
effacé) ne te sont pas familières, je t'encourage vivement à jouer avec
car c'est assez souvent utile.

note également que j'ai fourni une forme verbieuse des tests; en C/C++
toute expression non nulle (différente de zéro) est évaluée comme vrai donc:
if ((capsFlags & 1) == 1) {}
et
if (capsFlags & 1) {}

sont équivalents, dans les 2 cas on applique un "et binaire" à la
variable et on évalue le résultat qui est donc 'vrai' si le bit 1
(numéroté de 1 à n, de droite (LSB: less significant bit) à gauche (MSB:
more sig. bit)) de capsFlags est positionné (à 1), 'false' s'il est
effacé (à 0).

tu peux, bien sur, tester plusieurs bits à la fois:

if (capsFlags & 3) { au moins un flip est supporté }
ou
if ((capsFlags & 7) == 4) { un trigger externe mais aucun flip }

enfin, pour la lecture de ton code, il vaut mieux, bien sur, utiliser
des constantes nommées, ie:

if (capsFlags & VideoControlFlag_Trigger){
// le trigger est dispo, le traiter
}

</mode>

Sylvain.


Avatar
Michael
Merci pour tes éclaircissementss...

J'ai cependant une question:

je voudrais faire une fonction qui ajoute un enlève un bit selon qu'il soit
placé ou non...

Exemple simple:

enum t {
i = 0x0001,
j = 0x0002,
k = 0x0004,
l = 0x0008 };

long f(long l)
{
//1 n'est pas positionné, on l'ajoute
if ((x & 1) != 1)
x |= 1;
else
//On l'enlève
}

Comment faire pour n'enlever que cette valeur?

Merci :)
Avatar
Sylvain
Michael wrote on 01/11/2006 19:22:

long f(long l)
{
//1 n'est pas positionné, on l'ajoute
if ((x & 1) != 1)
x |= 1;
else
//On l'enlève
}

Comment faire pour n'enlever que cette valeur?


pour enlever une valeur seule, on fait un "et binaire" avec un mask où
ce bit est à 0 (pour l'effacer) et tous les autres à 1 (pour conserver
leurs valeurs courantes qlq soit k in (0,1), (k & 1) == k).

on obtient un tel mask via un "non binaire" sur ce bit.

soit: x &= ~1;

"1" est 000...001, not(1) ou ~1 donne 111...110

Sylvain.

Avatar
Loïc Joly
Merci pour tes éclaircissementss...

J'ai cependant une question:

je voudrais faire une fonction qui ajoute un enlève un bit selon qu'il soit
placé ou non...

Exemple simple:

enum t {
i = 0x0001,
j = 0x0002,
k = 0x0004,
l = 0x0008 };

long f(long l)
{
//1 n'est pas positionné, on l'ajoute
if ((x & 1) != 1)
x |= 1;
else
//On l'enlève
}


Pour inverser un bit directement, tu peux faire un ou exclusif avec la
valeur 1.

void f(long &x, long mask)
{
x ^= mask;
}

Ici, tous les bits de x dont le bit correspondant dans mask était à 1 on
inversé leur valeur.

Avatar
James Kanze
Michael wrote:
Merci pour tes éclaircissementss...

J'ai cependant une question:

je voudrais faire une fonction qui ajoute un enlève un bit
selon qu'il soit placé ou non...

Exemple simple:

enum t {
i = 0x0001,
j = 0x0002,
k = 0x0004,
l = 0x0008 };

long f(long l)
{
//1 n'est pas positionné, on l'ajoute
if ((x & 1) != 1)
x |= 1;
else
//On l'enlève
}


Plusieurs commentaires :

-- Sylvain s'est sans doute servi des valeurs numériques à
titre pédagogique, pour que tu vois exactement ce qui se
passe, mais dans la pratique, on utilise de préférence les
valeurs symboliques, c-à-d :
if ( (x & i) != 0 ) ...
De même, on utilise prèsque toujours une comparaison avec
zéro, pour ne pas être dépendant de la valeur numérique (et
pour ne pas avoir à répéter le symbole). Dans les cas où il
s'agit en fait des valeurs booléenes (à un bit), je trouve
que :
if ( x & i ) ...
est aussi acceptable, même si je ne m'en sers pas moi-même.

-- Une petite sommaire des opérations disponibles :

if ( x & i ) : test le bit, vrai s'il est à 1
x |= i ; le met à un
x &= ~i ; le rémet à zéro
x ^= i ; complémente le bit

Plus généralement, quand il s'agit des champs non booléens,
on aurait quelque chose du genre :

enum Toto
{
// ...
condA = 0x00 ,
condB = 0x10 ,
condC = 0x20 ,
condD = 0x30 ,
condMask = condA | condB | condC | condD ,
// ou carrément 0x30...
// ...
} ;

Pour lire le champs :

switch ( x & condMask ) {
case condA :
case condB :
// ...
}

Et pour le mettre à une valeur prédéterminée :

x = (x & ~condMask) | nouvelleValeur ;

Tout ça à condition que x soit une variable de type entier,
et non de type enum.

(Mais comme a dit Sylvain, il serait préférable que tu
apprends la représentation binaire et ses opérateurs, plutôt
que d'appliquer des formules à l'aveugle.)

-- Quand la définition de l'enum se trouve dans le C++ (ton
premier exemple suggérait du C), il n'est pas rare de
surcharger les opérateurs, pour pouvoir se servir des
opérations directement sur des variables de type enum. Donc,
on aurait :

t
operator|( t lhs, t rhs )
{
return (t)( (unsigned)lhs | (unsigned)rhs ) ;
}

et ainsi de suite, ce qui permet d'écrire :

t x = i | k ;
x |= j ;

Moi-même, j'ai pris l'habitude de surcharger également les
opérateurs + (même sémantique que |), - (a - b vaut a & ~b)
et * (&). Je ne sais pas si c'est une bonne idée ; ça frôle
vraiment l'abus du surcharge. Mais les opérateurs +, - et *
ont la bonne priorité, à l'encontre de | et &, et le - est
bien commode.

J'ai même un petit programme à ma site qui génère
automatiquement ces opérateurs (selon les options : il
génère aussi automatiquement un mapping vers texte, et pour
les enum classiques, les opérateurs d'incrémentation et de
decrémentation). Voir
http://kanze.james.neuf.fr/doc/man/man1/enumgen.man.html et
la description des « bitwise operators », et plus
généralement http://kanze.james.neuf.fr/code-fr.html pour
information sur le code en général.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34