我有一个问题需要快速解决方法,以享受非标准gnu case ranges带来的好处。例如,非标准:
case 1 ... 5:
可以替换为:
case 1:
case 2:
case 3:
case 4:
case 5:
可能有些宏观解决方案可能正常。从我的内存宏循环不能循环大量的迭代。出于这个原因,如果范围是“大”,比如成千上万,该怎么办?
答案 0 :(得分:2)
如果您正在谈论预处理器循环,我想您正在考虑boost
的预处理器元编程。虽然它可能非常便携,但循环似乎仅限于255
"迭代"。事实上,实现不是一个真正的循环,它更像是硬编码的循环展开(从而限制)。您当然可以将其扩展到更多迭代。
虽然预处理器技巧可能很诱人,但我认为你应该考虑使用if
- else if
- else
构造。在关于条件的现代编译器中实际(经常)发生的是它归结为应生成相同代码的相同构造(除非您欺骗编译器多次评估变量)。
您甚至可以使用switch
- case
构造为所有单个替代项合并构造,然后在default
标签后添加if-else if-else
来处理所有范围。
第三种解决方案是编写一个脚本来查找案例范围并用标准构造替换它们,这在大多数情况下应该相当直接,因为case
不能出现在很多地方如果不是关键字,那么它后面应该跟一个不能以这种方式包含...
的表达式。唯一有问题的情况(我能想到的)是case-range
是预处理器扩展的结果。
答案 1 :(得分:2)
最好的选择是重新分配代码以使用if / else。如果确实存在数千个案例,那么首先有一个巨大的案例陈述可能会或者可能不是非常有效。
然而,这是因为案件可以"堕落"或者像Duff的设备那样奇怪的流量控制(我希望不是),它可能不是一个简单的转换。
将预处理器滥用到"循环"不太可能是一个非常好的实现。有关此内容的示例,请参阅Writing a while loop in the C preprocessor。
最好编写一个简单的python或awk脚本。但是,如果关键字case出现在某个字符串之类的地方,或者如果标签预处理器发生了任何变化,那么这种方法也可能存在缺陷。这可能适用于狭窄的一次性转换,但是如果没有看到有问题的代码,很难说。
如果案例标签使用枚举,则预处理方法存在严重问题。由于枚举在预处理器运行时仍然只是文本字符串(或外部脚本),如何在不知道它们代表什么整数的情况下从STATE_10迭代到STATE_20?它不可能 - GNU扩展确实需要编译器支持。
如果一次性批发更换案例陈述过于侵入或不规范而无法管理,您可以采用混合方法:
假设你有一个(名义上的)例子:
switch(state)
{
case STATE_1:
xxx; break;
case STATE_2 ... STATE_10:
yyy; break;
}
分配以前未使用的索引范围。为每个现有范围标签添加一个新的特殊索引。使用if / else逻辑首先检测范围,然后用新的标准范围替换范围情况。这允许控制流结构基本上保持不变:
#if !defined(__GNUC__)
#define STATE_RANGE_2_10 101
if(state >= 2 && state <= 10)
state2 = STATE_RANGE_2_10
else if(...)
state2 = STATE_RANGE_x_y
else
state2 = state;
#else /* GNU */
#define STATE_RANGE_2_10 STATE_2 ... STATE_10
state2 = state;
#endif
switch(state2)
{
case STATE_1:
xxx; break;
case STATE_RANGE_2_10:
yyy; break;
}
使用一些合适的宏,如果你真的希望GNUC仍然因为某种原因仍然使用扩展,那么它甚至可以在GNUC和real C之间移植。注意:我介绍了state2变量,以防它在本地范围之外存储或使用。如果没有,你可以跳过它。