我正在阅读一些关于C语言
的文本。文本说switch{} case
只能接受整数类型。
我很好奇为什么switch{} case
不能接受其他类型,比如浮点数或字符串。这背后有什么原因吗?
非常感谢。
我正在阅读一些关于C语言
的文本。文本说switch{} case
只能接受整数类型。
我很好奇为什么switch{} case
不能接受其他类型,比如浮点数或字符串。这背后有什么原因吗?
非常感谢。
传统的理由可能是对于整数值的“决策表达式”,可以进行非常好的优化。
基本上,您可以将case语句列表映射到包含地址的表中,然后根据值直接跳转。显然,对于浮点数和字符串,这种方法行不通。
在GCC中,您可以使用一些扩展手动执行此操作,例如此处所述:
const char * digit_name(int d)
{
const void * handlers[] = { &&zero, &&one, &&two, &&three, &&four,
&&five, &&six, &&seven, &&eight, &&nine };
goto *handlers[d]; /* Assumes d is in range 0..9. */
zero: return "zero";
one: return "one";
two: return "two";
three: return "three";
four: return "four";
five: return "five";
six: return "six";
seven: return "seven";
eight: return "eight";
nine: return "nine";
return NULL;
}
通常称之为"计算跳转(computed goto)", 而且很明显可以将switch
编译成非常相似的东西。使用紧凑定义的开关表达式有所帮助,例如使用enum
。
此外,在C语言中并没有字符串的概念。
if (A)
{
}
else if (B)
{
}
else if (C)
{
}
else
{
}
switch(something)
{
case A:
{
break;
}
case B:
{
break;
}
case C:
{
break;
}
default:
{
break;
}
}
if-else switch
Symbols 33 65 // Not counting the expressions
Lines 12 19 // Not counting empty lines
if (A) {}
else if (B) {}
else if (C) {}
else {}
switch(something)
{
case A: { break; }
case B: { break; }
case C: { break; }
default: { break; }
}
switch
可能出于审美、迷信或宗教原因,但我更愿意将这样的非主题讨论留给与编程无关的网站。
typedef void (*Func_t)(void);
const Func_t cases [N] = { ... };
cases[i]();
C语言的语言哲学就是所见即所得,没有隐藏机制。这实际上是该语言的一大优势。
对整数进行开关操作涉及到预期的分支,而对浮点数和字符串进行比较会有隐藏的代价。
浮点数值通常不直接可比
x = 1 / 3.0;
switch (x) {
case 0.3333: /* ... */; break;
case 0.333333333875634875634: /* ... */; break;
case 0.333333333784532452321: /* ... */; break;
case 0.333333333847632874632: /* ... */; break;
default: break;
}
对于字符串也是如此(不要使用strcpy(buff, "foobar"); if (buff == "foobar") /* ... */;
)
当有离散的选项时,开关可能是最好的选择。编译器可以警告您重复的情况,如果您使用枚举,则良好的编译器将警告未处理的值。
作为一种良好的实践,浮点数/双精度不应测试相等,“if(f = 3.141516)”会引起头痛,“const float kEpsilon = 1e-5;”,然后使用“if(fabs(f - 3.141516)< kEpsilon)”选择与您的问题相关的epsilon值。内联函数或宏可以帮助以更可读的方式编写此内容。
我们不能在 switch case 中使用 float。这是因为浮点数不精确。你永远不知道那个数字实际上会是什么。
浮点数的比较由于舍入误差不可靠,而C语言默认不支持字符串比较(只能通过函数strcmp等实现)。
-> 没有办法让编译器自动确定比较方法。
switch
语句通常不会被排序,因为如果它们没有以break
结尾,它们可能会重叠。更一般地说,case
标签只是任意嵌套语句块中的标签。 - Jens Gustedt