编译器如何处理case语句?

时间:2017-03-19 08:12:11

标签: delphi if-statement switch-statement

the documentation案例陈述中,它说:

  

caseList表示的每个值在这种情况下必须是唯一的   语句;

显示的例子,

case I of
  1..5: Caption := 'Low';
  6..9: Caption := 'High';
  0, 10..99: Caption := 'Out of range';
else
  Caption := ;
end

等同于嵌套条件:

if I in [1..5] then
  Caption := 'Low';
else if I in [6..10] then
  Caption := 'High';
else if (I = 0) or (I in [10..99]) then
  Caption := 'Out of range'
else
  Caption := ;

所以第一个引用表明它被处理成一个集合(阅读评论here至少有一个人与我在一起)。

现在我知道了部分

  

其中selectorExpression是序数类型较小的任何表达式   超过32位

与集合的属性相矛盾,因为在集合中提到her

  

基类型可以具有不超过256个可能的值,以及它们的值   序数必须介于0到255之间

真正困扰我的是为什么在caseList中拥有唯一值是必要的。如果它等同于if语句,那么第二个值将不会被测试,因为编译器已经找到了先前的匹配项?

2 个答案:

答案 0 :(得分:10)

该文档采用特定 案例语句,该语句相当于特定 if 语句。

通常,任何 case 语句都可以使用相同的方法重写为 if 语句。但是,相反的情况并非如此。

文档使用等效的 if 语句来解释 case 语句的逻辑行为(或语义)。它不是编译器内部工作的表示。

  

编译器如何处理case语句?

首先请注意这个问题有两个方面。

  • 语义编译器必须按照文档中的说明处理case语句。这包括:
    • 确保每个 caseList 条目的值可以在编译时进行评估。
    • 确保 caseList 条目是唯一的。
    • 无论 caseList 条目匹配,都会调用相应的caseList语句。
    • 如果没有 caseList 条目匹配,则调用else语句。
  • 但是,如果优化的字节/机器代码在逻辑上等效,编译器有权优化其认为合适的实现。
    • Johan's answer描述了常见的优化:跳转列表和重新排序。
    • 鉴于严格的语义,这些更容易应用。
  

真正困扰我的是为什么在 caseList 中拥有唯一值是必要的。

消除歧义需要唯一性。如果多个匹配,应该使用哪个caseList语句?

  • 它可以调用第一个匹配的caseList语句并忽略其余的。 (SQL Server CASE语句的行为与此类似。)另请参阅下面的[1]
  • 它可以打电话给所有人。 (如果我没记错的话,MANTIS编程语言将其语义用于案例陈述的版本。)
  • 它可能会报告错误,要求程序员消除 caseList 的歧义。 (简而言之,这就是德尔福规范所要求的。许多其他语言使用相同的方法。对它进行狡辩是非生产性的,特别是因为这种选择不太可能是一个障碍。)
  

如果它等同于if语句,则第二个值将不会被测试,因为编译器已经找到了先前的匹配。

[1]我想指出,这会使代码更难以阅读。使用魔术文字时,此行为是“正常”,但使用const标识符时,这会变得很危险。如果2个不同的consts具有相同的值,则不会立即显示 caseList 匹配的后一个caseList语句将不会被调用。由于简单的 caseList 重新排序,案例陈述也会受到行为改变的影响。

const
  NEW_CUSTOMER = 0;
  EDIT_CUSTOMER = 1;
  ...
  CANCEL_OPERATION = 0;

case UserAction of
  NEW_CUSTOMER : ...;
  EDIT_CUSTOMER : ...;
  ...
  CANCEL_OPERATION : ...; { Compiler error is very helpful. }
end;
  

与集合属性相矛盾

没有矛盾。每个 caseList 值必须唯一的事实并不意味着它必须“像集合一样处理”。那是你不正确的假设。其他人做出同样的假设同样是错误的。

如何检查唯一性约束取决于编译器。我们只能推测。但我猜最有效的方法是维护一个有序的范围列表。遍历每个 caseList 的值和范围,在上面的列表中找到它的位置。如果它重叠,则报告错误,否则将其添加到列表中。

答案 1 :(得分:6)

案例陈述
编译器更喜欢将case语句转换为跳转表 为了使这种可能的重复案例标签不被允许。

此外,编译器不必按照您声明的顺序测试case语句。出于优化原因,它会根据需要重新排序这些元素;因此,即使它不使用跳转表,它仍然不能允许重复的案例标签。

出于同样的原因(并且让程序员在精神上保持理智),case语句不允许堕落。

if statement
一系列(一系列)if语句按声明的顺序处理 编译器将逐个测试它们(并在适当时跳出) 如果if语句不包含重复项,则代码将执行与等效case语句相同的操作,但生成的代码很可能不同。
如果语句永远不会转换为跳转表。

关于集合
原因集限制为256个元素,即集合中的每个元素占用一位空间 256位= 32字节 允许一组中超过256个元素会使内存中的表示过多,从而影响性能。

case语句不使用集合,它只是在其语义中使用set逻辑。