可读性与可维护性:将语句压缩为循环

时间:2013-12-30 03:41:11

标签: c performance winapi readability maintainability

首先,我所指的一个例子:

UINT f, i, s;
CONST UINT k[5] = { VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2 };

for (f = RI_MOUSE_LEFT_BUTTON_DOWN, i = 0, s = RI_KEY_MAKE; f != RI_MOUSE_WHEEL; f <<= 1, i += s, s = !s)
    if ((pMouseData->usButtonFlags & f) == f)
        SetVKeyState(k[i], s);

与此相比:

if (pMouseData->usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
    SetVKeyState(VK_LBUTTON, RI_KEY_MAKE);

if (pMouseData->usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
    SetVKeyState(VK_LBUTTON, RI_KEY_BREAK);

if (pMouseData->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
    SetVKeyState(VK_RBUTTON, RI_KEY_MAKE);

if (pMouseData->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
    SetVKeyState(VK_RBUTTON, RI_KEY_BREAK);

if (pMouseData->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
    SetVKeyState(VK_MBUTTON, RI_KEY_MAKE);

if (pMouseData->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
    SetVKeyState(VK_MBUTTON, RI_KEY_BREAK);

if (pMouseData->usButtonFlags & RI_MOUSE_X1_BUTTON_DOWN)
    SetVKeyState(VK_XBUTTON1, RI_KEY_MAKE);

if (pMouseData->usButtonFlags & RI_MOUSE_X1_BUTTON_UP)
    SetVKeyState(VK_XBUTTON1, RI_KEY_BREAK);

if (pMouseData->usButtonFlags & RI_MOUSE_X2_BUTTON_DOWN)
    SetVKeyState(VK_XBUTTON2, RI_KEY_MAKE);

if (pMouseData->usButtonFlags & RI_MOUSE_X2_BUTTON_UP)
    SetVKeyState(VK_XBUTTON2, RI_KEY_BREAK);

后面的代码显然是一个完全展开的循环。

这实际上是一个关于可读性减少冗余(在代码的不同区域中的重复语句中)是否从长远来看更好的问题。

我更关心稍后在大型代码库的上下文中访问它。当然,减少修改区域的数量是一件好事; for循环的初始化和更新语句是否有点麻烦?

有没有人经历过这个,可能是微不足道的问题。

1 个答案:

答案 0 :(得分:4)

关键是只压缩完全相同的陈述:

const UINT k[5] = { VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2 };

static_assert( (RI_MOUSE_LEFT_BUTTON_DOWN << 2) == RI_MOUSE_RIGHT_BUTTON_DOWN );

for ( UINT i = 0; i < _count_of(k); ++i ) {
    if (pMouseData->usButtonFlags & (RI_MOUSE_LEFT_BUTTON_DOWN << 2*i))
        SetVKeyState(k[i], RI_KEY_MAKE); 
    if (pMouseData->usButtonFlags & (RI_MOUSE_LEFT_BUTTON_UP << 2*i)))
        SetVKeyState(k[i], RI_KEY_BREAK); 
}

所有逗号运算符都消失了,异常的循环增量消失了,符号变量仍然用于键状态。

我认为这比原版更容易阅读,因为它适用于一页代码,重复很明显。

编辑:现在记录了旗帜关系假设。

我实际上可能会:

struct { UINT vk;      UINT downflag;                 UINT upflag;
} const k[] = {
       { VK_LBUTTON,   RI_MOUSE_LEFT_BUTTON_DOWN,     RI_MOUSE_LEFT_BUTTON_UP },
       { VK_RBUTTON,   RI_MOUSE_RIGHT_BUTTON_DOWN,    RI_MOUSE_RIGHT_BUTTON_UP },
    ...
};
for ( UINT i = 0; i < _count_of(k); ++i ) {
    if (pMouseData->usButtonFlags & k[i].downflag)
        SetVKeyState(k[i].vk, RI_KEY_MAKE); 
    if (pMouseData->usButtonFlags & k[i].upflag)
        SetVKeyState(k[i].vk, RI_KEY_BREAK); 
}

以正确的顺序删除使用相邻位的标志的假设。

可以使用后一个版本,使第二个参数成为SetVKeyState一个表列,但IMO失去了有价值的配对结构。

相关问题