2 votes

Comportement étrange du programme et de l'instruction if du débogueur

C'est un contrôle de bon sens parce que j'ai perdu le mien.

J'ai une méthode IsCaptured() qui compare un membre de l'état d'un enum à une valeur donnée et renvoie un bool . Je l'utilise en conjonction avec une vérification du seuil de la souris pour déterminer si un message de début de déplacement doit être envoyé et si une opération de déplacement doit commencer. Le problème est que ce message est déclenché par le déplacement de la souris alors qu'il ne devrait pas l'être. J'ai ajouté les messages de trace suivants :

TRACE(L"%s\n", (IsCaptured()) ? L"true" : L"false");
CPoint delta = pt - m_trackMouse;
static CPoint thresh(GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));

if (IsCaptured() &&
    abs(delta.x) >= thresh.x || abs(delta.y) >= thresh.y)
{
    TRACE(L"%s\n", (IsCaptured()) ? L"true" : L"false");
    // Send message to enter drag mode
    bool bDrag = ::SendMessage(m_trackWnd, WM_DD_BEGIN, ::GetDlgCtrlID(m_trackWnd), (LPARAM)(void*)&m_info) != 0;

    // ...
}

Maintenant la partie étrange, la sortie :

false
false

La méthode est mise en œuvre comme suit et m_dragState est réglé sur NONE jusqu'à ce qu'il y ait un bouton vers le bas intercepté :

enum { NONE, CAPTURED, DRAGGING };
bool IsCaptured() const { return m_dragState == CAPTURED; }

J'ai essayé de reconstruire la solution entière, sans succès. J'utilise VS2010 Debug 64-bit et le programme est une application MFC à un seul thread. Qu'est-ce qui se passe ici ?

8voto

AndreyT Points 139512

Il n'y a rien d'étrange dans vos résultats. && a une priorité plus élevée que || c'est pourquoi votre

if (IsCaptured() &&
    abs(delta.x) >= thresh.x || abs(delta.y) >= thresh.y)

est interprété comme

if ((IsCaptured() && abs(delta.x) >= thresh.x) || 
    abs(delta.y) >= thresh.y)

C'est-à-dire que si le abs(delta.y) >= thresh.y est remplie, alors le résultat de l'ensemble de l'analyse de la if ne dépend pas de votre IsCaptured() du tout.

Le compilateur ne se soucie pas que vous ayez "exprimé" votre intention par des sauts de ligne. La précédence des opérateurs compte. Les sauts de ligne ne le sont pas.

Ce que vous aviez apparemment l'intention de faire était

if (IsCaptured() && 
    (abs(delta.x) >= thresh.x || abs(delta.y) >= thresh.y))

Notez le placement d'accolades supplémentaires autour des opérandes de || sous-expression.

1voto

w00te Points 11664

Pensez-y comme :

(IsCaptured() && abs(delta.x) >= thresh.x || abs(delta.y) >= thresh.y)

ceci :

 (false && true) || true

Votre IsCaptured() n'a pas besoin d'être vrai pour progresser, il peut donc très bien être faux dans les deux impressions.

0voto

thiton Points 21303

Vous devriez probablement vous assurer d'abord que les deux faux ne se réfèrent pas tous deux à la première ligne de traçage.

Si la deuxième ligne de traçage affiche false ici, vous avez probablement une condition de course classique entre les mains et vous devez vous en protéger.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X