考虑下面的switch语句:
switch( value )
{
case 1:
return 1;
default:
value++;
// fall-through
case 2:
return value * 2;
}
此代码编译,但它是有效的(=定义的行为)C90/C99?我从未见过默认情况不是最后一个情况的代码。
编辑:
正如Jon Cage和KillianDS所写的:这真的是丑陋而令人困惑的代码,我很清楚这一点。我只对通用语法(有定义吗?)和预期的输出感兴趣。
我有一个有趣的例子,把默认值放在顶部保存的程序空间。它是为Arduino Nano设计的,节省了8字节的闪存(RAM是一样的)。
供你参考,这两组代码是
#if 1 // toggle this 0 or 1
// 3138/265 bytes
uint8_t g_BuiltinLedGlowState = 0; // dropping '= 0' saves nothing
void AdvanceBuiltinLedGlow_3Ph(){
switch(++g_BuiltinLedGlowState){
default:
g_BuiltinLedGlowState = 0;
// drop through // break;
case 0: // bright
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
break;
case 1: // dim
pinMode(LED_BUILTIN, INPUT_PULLUP);
break;
case 2: // off
pinMode(LED_BUILTIN, INPUT);
break;
}
}
#elif 1
// 3146/265 bytes
uint8_t g_BuiltinLedGlowState = 0; // dropping '= 0' saves nothing
void AdvanceBuiltinLedGlow_3Ph(){
switch(++g_BuiltinLedGlowState){
case 1: // bright
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
break;
case 2: // dim
pinMode(LED_BUILTIN, INPUT_PULLUP);
break;
case 3: // off
pinMode(LED_BUILTIN, INPUT);
// drop through // break;
default:
g_BuiltinLedGlowState = 0;
break;
}
}
#endif
// the loop function runs over and over again forever
void loop() {
Serial.println(g_BuiltinLedGlowState, DEC);
AdvanceBuiltinLedGlow_3Ph();
delay(1000);
}
这是合理的,但相当令人讨厌。我的建议是,允许出现漏洞通常是不好的,因为它会导致一些非常混乱的意大利面条代码。
将这些情况分解成几个switch语句或更小的函数几乎肯定更好。
@Tristopia:你的例子:
Example from UCS-2 to UTF-8 conversion
r is the destination array,
wc is the input wchar_t
switch(utf8_length)
{
/* Note: code falls through cases! */
case 3: r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800;
case 2: r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0;
case 1: r[0] = wc;
}
(我认为)如果它是这样写的,它的意图会更清楚:
if( utf8_length >= 1 )
{
r[0] = wc;
if( utf8_length >= 2 )
{
r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0;
if( utf8_length == 3 )
{
r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800;
}
}
}
[edit2] @Tristopia:你的第二个例子可能是follow-through用法最清晰的例子:
for(i=0; s[i]; i++)
{
switch(s[i])
{
case '"':
case '\'':
case '\\':
d[dlen++] = '\\';
/* fall through */
default:
d[dlen++] = s[i];
}
}
..但就我个人而言,我会把评论识别分解成它自己的功能:
bool isComment(char charInQuestion)
{
bool charIsComment = false;
switch(charInQuestion)
{
case '"':
case '\'':
case '\\':
charIsComment = true;
default:
charIsComment = false;
}
return charIsComment;
}
for(i=0; s[i]; i++)
{
if( isComment(s[i]) )
{
d[dlen++] = '\\';
}
d[dlen++] = s[i];
}
默认条件可以是开关中case子句可以存在的任何位置。它不需要是最后一个子句。我曾见过将默认值作为第一个子句的代码。情况2:正常执行,即使默认子句在它上面。
作为测试,我把示例代码放在一个名为test(int value){}的函数中,并运行:
printf("0=%d\n", test(0));
printf("1=%d\n", test(1));
printf("2=%d\n", test(2));
printf("3=%d\n", test(3));
printf("4=%d\n", test(4));
输出结果为:
0=2
1=1
2=4
3=8
4=10