除了 -Wall 和 -Wextra 之外,还有哪些其他工具可以用来发现尽可能多的错误或警告?

Apart from -Wall and -Wextra what other tools are available to spot as many errors or warnings as possible?

下面的代码完美地计算了一个数的阶乘。

#include <stdio.h>

long int f_fact(int i);

int main() {
    int a;
    long int factorial;

    printf("Please enter a number\n");
    scanf("%d", &a);

    factorial = f_fact(a);
    printf("The factorial is %ld\n", factorial);

    return 0;
}

long int f_fact(int i) {
    int j;
    long int factorial = 1;

    for (j = 2; j <= i; ++j) {
        factorial = factorial * j;
    }
    return (factorial);
}

但是,其他代码没有。唯一的区别是使用 for (j = 2; j <= i; ++i) 而不是 for (j = 2; j <= i; ++j)

#include <stdio.h>

long int f_fact(int i);

int main() {
    int a;
    long int factorial;

    printf("Please enter a number\n");
    scanf("%d", &a);

    factorial = f_fact(a);
    printf("The factorial is %ld\n", factorial);

    return 0;
}

long int f_fact(int i) {
    int j;
    long int factorial = 1;

    for (j = 2; j <= i; ++i) {
        factorial = factorial * j;
    }
    return (factorial);
}

我的问题是如何才能最好地发现代码中的这些小错误?现在,我激活了 -Wall-Wextra,但即使有了这些,我也得到了:Errors: 0Warnings: 0,这使得发现问题有点困难。有什么建议可以更好地解决错误吗?谢谢!

编译器不能检查逻辑错误。您可能是有意编写该指令的。

哦,要检查几个自动检测的问题,GCC 知道 -pedantic,但请阅读完整的文档。你可能想试试 clang 的功能。

这是单元测试发挥作用的领域。从一本好书开始,尝试一些框架,然后测试你的逻辑。

"My question is how can I best spot these little mistakes in the code?"

不幸的是,没有编译器选项可以检测逻辑问题,GCC 和 Clang 都没有。

在可以插入相同类型对象的地方使用放错位置的对象是编译器无法检测到的,因为这是一个合乎逻辑的问题。编译器只能检测 语法 问题。

如果没有内存被认为是损坏的,它甚至不能被一些额外的代码分析器工具找到,比如 f.e。 AddressSanitizer 或 Valgrind。

要防止此类错误,您唯一可以做的就是在编码时必须小心。

避免过于频繁地复制和粘贴,而是通过单独编写代码部分来明确重点。

关于所提供的问题,避免复制循环头或部分循环头,尤其是在嵌套循环内部。


但是要回答你的问题:

Apart from -Wall and -Wextra what other tools are available to spot as many errors or warnings as possible?

例如 GCC 有 -Wpedantic/-pedantic-Wall-Werror

您可以在此处找到它们以及更多内容,并列出它们的相关解释:

https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options


对于 Clang,您有 f.e。 -Weverything。您可以在此处找到诊断选项列表及其说明:

https://clang.llvm.org/docs/DiagnosticsReference.html

您已经知道并使用了 -Wall -Wextra,可以用 -Werror 来完成,通过标记一些经典问题来检测潜在的错误。

虽然您可以添加更多编译器选项来尝试检测其他问题,但很难检测到逻辑错误。例如,如果设置了一个变量但未使用,可以检测到简单的拼写错误,但您的错误仍然不会被注意到。

其他预防措施包括编码风格和命名约定:非常严格的风格规则,尤其是 space 和缩进的一致使用,有助于使代码更具可读性并减少 space 愚蠢的错误隐藏。命名约定也有帮助:在您的示例中,不应将参数命名为 i,而应命名为 ni 是索引变量的默认名称,正如您自己所经历的那样,因此正确命名参数可以有效地避免这个错误:

long int f_fact(int n) {
    long int factorial = 1;

    for (int i = 2; i <= n; i++) {
        factorial *= i;
    }
    return factorial;
}

除了 -Wall -Wextra(和 -Weverything 用于 clang)之外,我还为我的项目使用了一些额外的标志:

  • 避免潜在签名 char 类型的问题:-funsigned_char -Wchar-subscripts
  • 防止 printf 具有可变格式字符串:-Wformat-nonliteral
  • 生成字符串文字 const: -Wwrite-strings