关于C中的开关{}情况?
我正在读一些C语言的文本。文本说明关于C中的开关{}情况?,c,switch-statement,C,Switch Statement,我正在读一些C语言的文本。文本说明开关{}case只能接受整数类型 我只是好奇为什么switch{}case不接受其他类型,比如float或string。这背后有什么原因吗 非常感谢。经典原因可能是对于整数值“决策表达式”,可以进行非常好的优化 基本上,您可以将case语句列表映射到包含地址的表,然后直接基于该值跳转。显然,对于不起作用的浮点数和字符串 在GCC中,您可以手动使用以下命令: 这通常被称为“计算的转到”,应该清楚地知道开关基本上是如何编译成非常类似的东西的。对已打开表达式的严格定义
开关{}case
只能接受整数类型
我只是好奇为什么switch{}case
不接受其他类型,比如float或string。这背后有什么原因吗
非常感谢。经典原因可能是对于整数值“决策表达式”,可以进行非常好的优化 基本上,您可以将case语句列表映射到包含地址的表,然后直接基于该值跳转。显然,对于不起作用的浮点数和字符串 在GCC中,您可以手动使用以下命令: 这通常被称为“计算的转到”,应该清楚地知道
开关
基本上是如何编译成非常类似的东西的。对已打开表达式的严格定义很有帮助,例如使用enum
此外,C在语言层面上并没有太多字符串的概念。由于舍入错误,浮点值的比较不可靠,C默认不支持字符串比较(例如,仅通过函数strcmp)
->编译器无法自动确定比较方法。简单的回答是整数类型易于比较,而且比较速度非常快。C中的浮点类型无法可靠地进行比较。我不认为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”)/*…*/;
)C语言的哲学是看到的就是得到的。没有隐藏的机制。这实际上是语言的强大力量之一
打开integer会像预期的那样进行分支,而比较float和string会有隐藏的代价。我会用一个问题来回答:为什么要使用switch语句而不是if…else if? 令人惊讶的是,许多程序员从不问这个问题,而是把
switch
看作是语言中必须具备的基本要素。那不是真的!您可以编写任何类型的C程序,而无需使用开关
。严格来说,开关
是一种冗余功能
那为什么要用它呢
可读性不是原因<代码>开关实际上比if-else的语法更糟糕、更不直观。开关内部需要break语句,开关的奇怪语法规则允许一个案例在另一个案例的本地范围内声明,默认的任意位置
开关
不仅可读性较差,而且比其他开关更容易出现错误。被遗忘的中断是最明显的危险,它导致了数百万个软件中难以发现的错误
另一个反对switch
更具可读性的更明显的论点是这段“裸骨”代码:
上面的if和switch在语法和功能上是等价的,应该编译成完全相同的机器代码。下面是这个例子的统计数据
if-else switch
Symbols 33 65 // Not counting the expressions
Lines 12 19 // Not counting empty lines
对于相同的结果,switch需要更多的代码,因此必须将is视为不如if-else可读
在您开始争论交换机看起来更像一个表而不是其他表之前,这都是关于代码格式的问题,而且与此无关。标准中没有任何内容阻止您编写以下代码:
if (A) {}
else if (B) {}
else if (C) {}
else {}
switch(something)
{
case A: { break; }
case B: { break; }
case C: { break; }
default: { break; }
}
我会认为这两种形式都是可读的,如果你希望得到一些类似表的语法。
当然,出于审美、迷信或宗教原因,应该使用switch
以提高可读性,但我宁愿将此类离题讨论留给与编程无关的网站
所以这个开关比其他开关更不安全,可读性也更低。然后剩下的可能吸引程序员的是效率。一个拥有n个必须由程序测试的用例的程序员肯定会希望能够尽快找到正确的用例。以线性方式检查所有案例是个坏主意 您可能知道,通过将if-else或switch实现为函数指针数组,可以对其进行大量优化:
typedef void (*Func_t)(void);
const Func_t cases [N] = { ... };
cases[i]();
这种剧烈的优化通常正是编译器遇到switch语句时所做的。但是,只有当所有情况都是相邻整数时,才能进行此优化。如果它们不相邻,则可以通过常量查找表创建相邻关系
但如果案例不是整数类型,则无法进行上述优化。如果它们是浮点数、字符串或其他东西,则没有合理的方法来优化代码
因此,至少在我的书中,switch
的存在就是为了这个目的:它使编译器更容易创建更有效的代码。因此,它与关键字inline、register等属于同一类,这也使编译器更容易优化代码。您必须考虑“如何将此C代码转换为汇编?”
switch conditional只是某种复杂的JMP指令,顺便说一句,它需要在编译之前对案例进行排序(我想编译器会对您的案例进行排序),但我不太确定
例如,在php中,您可以使用字符串切换{},这可能会使用某种二分法搜索(它首先查找第一个字符,等等),就像映射一样
您必须了解编译语言是生成“相当好”的汇编代码的一种方式,但这并不意味着它会比您在汇编中编写程序更好
使用C语言或C++语言,你将快速地编写程序。
if (A) {}
else if (B) {}
else if (C) {}
else {}
switch(something)
{
case A: { break; }
case B: { break; }
case C: { break; }
default: { break; }
}
typedef void (*Func_t)(void);
const Func_t cases [N] = { ... };
cases[i]();