运行-一次调节的宏
Macro for run-once conditioning
我正在尝试构建一个只运行一次代码的宏。
非常有用,例如,如果您循环代码并希望内部的某些事情只发生一次。简单易用的方法:
static int checksum;
for( ; ; )
{
if(checksum == 0) { checksum == 1; // ... }
}
但是有点浪费和混乱。所以我有这个宏,它使用检查位而不是检查变量的 true/false 状态:
#define CHECKSUM(d) static d checksum_boolean
#define CHECKSUM_IF(x) if( ~(checksum_boolean >> x) & 1) \
{ \
checksum_boolean |= 1 << x;
#define CHECKSUM_END }1
末尾的1
是强制用户在末尾加上分号。在我的编译器中这是允许的。
问题是弄清楚如何在无需用户指定 x
的情况下执行此操作(要检查 n 位)。
所以他可以使用这个:
CHECKSUM(char); // 7 run-once codes can be used
for( ; ; )
{
CHECKSUM_IF
// code..
CHECKSUM_END;
}
想法我怎样才能做到这一点?
我猜你是说你希望宏以某种方式自动跟踪你的位掩码的哪一位包含当前测试的标志。你可以这样做:
#define CHECKSUM(d) static d checksum_boolean; \
d checksum_mask
#define CHECKSUM_START do { checksum_mask = 1; } while (0)
#define CHECKSUM_IF do { \
if (!(checksum_boolean & checksum_mask)) { \
checksum_boolean |= checksum_mask;
#define CHECKSUM_END \
} \
checksum_mask <<= 1; \
} while (0)
#define CHECKSUM_RESET(i) do { checksum_boolean &= ~((uintmax_t) 1 << (i)); } while (0)
你可以这样使用:
CHECKSUM(char); // 7 run-once codes can be used
for( ; ; )
{
CHECKSUM_START;
CHECKSUM_IF
// code..
CHECKSUM_END;
CHECKSUM_IF
// other code..
CHECKSUM_END;
}
但是请注意,这有 严重 限制:
CHECKSUM_START
宏和所有对应的 CHECKSUM_IF
宏必须出现在同一范围内
- 控件必须始终在任何
CHECKSUM_IF
块之前通过 CHECKSUM_START
- 控件必须始终以相同的顺序到达
CHECKSUM_IF
块。如果它还跳过所有使用相同校验和位掩码的后续块,它可能只会跳过 CHECKSUM_IF
块。
出现这些限制是因为预处理器无法计数。
换句话说,除非重新定义宏,否则没有任何参数的宏总是会扩展为完全相同的文本。因此,如果您不使用宏参数来指示在每种情况下应用哪个标志位,则需要在 运行 时间进行跟踪。
我正在尝试构建一个只运行一次代码的宏。 非常有用,例如,如果您循环代码并希望内部的某些事情只发生一次。简单易用的方法:
static int checksum;
for( ; ; )
{
if(checksum == 0) { checksum == 1; // ... }
}
但是有点浪费和混乱。所以我有这个宏,它使用检查位而不是检查变量的 true/false 状态:
#define CHECKSUM(d) static d checksum_boolean
#define CHECKSUM_IF(x) if( ~(checksum_boolean >> x) & 1) \
{ \
checksum_boolean |= 1 << x;
#define CHECKSUM_END }1
末尾的1
是强制用户在末尾加上分号。在我的编译器中这是允许的。
问题是弄清楚如何在无需用户指定 x
的情况下执行此操作(要检查 n 位)。
所以他可以使用这个:
CHECKSUM(char); // 7 run-once codes can be used
for( ; ; )
{
CHECKSUM_IF
// code..
CHECKSUM_END;
}
想法我怎样才能做到这一点?
我猜你是说你希望宏以某种方式自动跟踪你的位掩码的哪一位包含当前测试的标志。你可以这样做:
#define CHECKSUM(d) static d checksum_boolean; \
d checksum_mask
#define CHECKSUM_START do { checksum_mask = 1; } while (0)
#define CHECKSUM_IF do { \
if (!(checksum_boolean & checksum_mask)) { \
checksum_boolean |= checksum_mask;
#define CHECKSUM_END \
} \
checksum_mask <<= 1; \
} while (0)
#define CHECKSUM_RESET(i) do { checksum_boolean &= ~((uintmax_t) 1 << (i)); } while (0)
你可以这样使用:
CHECKSUM(char); // 7 run-once codes can be used
for( ; ; )
{
CHECKSUM_START;
CHECKSUM_IF
// code..
CHECKSUM_END;
CHECKSUM_IF
// other code..
CHECKSUM_END;
}
但是请注意,这有 严重 限制:
CHECKSUM_START
宏和所有对应的CHECKSUM_IF
宏必须出现在同一范围内- 控件必须始终在任何
CHECKSUM_IF
块之前通过CHECKSUM_START
- 控件必须始终以相同的顺序到达
CHECKSUM_IF
块。如果它还跳过所有使用相同校验和位掩码的后续块,它可能只会跳过CHECKSUM_IF
块。
出现这些限制是因为预处理器无法计数。
换句话说,除非重新定义宏,否则没有任何参数的宏总是会扩展为完全相同的文本。因此,如果您不使用宏参数来指示在每种情况下应用哪个标志位,则需要在 运行 时间进行跟踪。