'else if' 在这个函数中是多余的吗?

Is the 'else if' redundant in this function?

所以,在C程序中用下面的函数来判断一个数是质数还是合数:

/** 
 * Determine if a given integer is prime. O(sqrt n).
 * n: The integer to examine.
 * return: TRUE if n is prime; FALSE if n is not prime.
 */
BOOL APIENTRY IsPrime(int n)
{
    int i;
    double test;
    if(n <= 1) return FALSE;
    else if(n <= 3) return TRUE; // Is the else keyword at beginning of this line useful?

    for(i = 2; i <= sqrt(n); i++)
    {
        test = (double) n / (double) i;
        if (test == floor(test)) return FALSE;
    }
    return TRUE;
}

如果我用 if (n <= 3) return TRUE; 替换第 12 行,该函数仍然可以正常工作(因为前面的 if 语句捕获了 n 不是质数的情况,前提是它是 1, 0或负数)。不管怎样,我都应该保留 else 关键字吗?

if(n <= 1) return FALSE;
else if(n <= 3) return TRUE;

if(n <= 1) return FALSE;
if(n <= 3) return TRUE;

相同,因为 return FALSE; 结束当前函数的执行(与任何 return 语句一样)。所以生成的汇编代码应该是相同的,你可以保留或不保留它,因为你觉得更易读。

由你决定,真的

此外,i从2开始,所以是的,你可以丢弃它。


题外话:为什么要用浮点运算?你想找到质数。你可能会遇到问题,小心!

如果你的编译器足够聪明,在if之前有或没有else编译后的代码都是一样的。

但是,在您的代码中,您写道:

for (...; n<= sqrt(n); ...)

哪个可以(再次取决于编译器)在每次循环迭代时调用 sqrt 函数。

替换为:

int limit = sqrt(n);
for (i = 3; i <= limit; i +=2)
    ...

是的,if 分支无条件返回后的 else 总是多余的:

if (someCondition) {
    ... do something, then
    return someValue;
} // <<== An "else" here would be redundant
... more code

到达"more code"行的唯一方法是someCondition计算为false,这与到达else分支的条件相同。

if分支与其他类型的无条件控制转移也是如此,例如breakcontinue。存在代码分析工具来警告程序员冗余。

在这种情况下,它是无关紧要的,因为您是在 return 编写代码。在这两种情况下,编译后的代码都会在 n > 1 时跳转到 if (n <= 3),无论如何。

这是因为如果第一个 if 语句为假,则必须始终评估第二个条件。这在两个函数的汇编器输出中很容易看出(并且应该始终直接验证):

Ltmp7:
    cmpl    , %edi
    jge LBB0_2
    xorl    %eax, %eax
    jmp LBB0_8 // jump to return false
LBB0_2:
    movb    , %r14b
    cmpl    , %edi
    jl  LBB0_3 // jump to return true

Ltmp15:
    cmpl    , %edi
    jge LBB1_2
    xorl    %eax, %eax
    jmp LBB1_8 // jump to return false
LBB1_2:
    movb    , %r14b
    cmpl    , %edi
    jl  LBB1_3 // jump to return true

将代码修改为类似

if (n <= 3) return n > 1;

因为现在你只有一个分支,所以它可以进行不同的优化,例如在我的编译器 (clang-3.4) 上它产生

cmpl    , %edi
jge LBB0_1 // jump to function body
cmpl    , %edi
setg    %al
jmp LBB0_7 // jump to return with $al register already set

其中使用setg指令直接根据前面的比较设置return值