【问题标题】:Apart from -Wall and -Wextra what other tools are available to spot as many errors or warnings as possible?除了 -Wall 和 -Wextra 之外,还有哪些工具可以用来发现尽可能多的错误或警告?
【发布时间】:2020-08-19 09:31:17
【问题描述】:

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

#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 &lt;= i; ++i) 而不是这个for (j = 2; j &lt;= 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,这使得发现问题有点困难。有什么建议可以更好地解决错误吗?谢谢!

【问题讨论】:

  • 我认为这不可能。这是代码逻辑中的错误,我很确定编译器还不够聪明,无法将逻辑错误与逻辑合理的代码区分开来。我的意思是,如果您出于某种原因确实 打算在那里增加i 怎么办?编译器是否应该以某种方式猜测您正在编写阶乘函数?
  • 我明白你的意思@ForceBru 感谢您的快速回复! :-)
  • clang -Weverything... 使用几种不同的编译器会增加警告
  • 使用 clang 的 UndefinedBehaviorSanitizer 您可以发现更多问题,但在您的情况下,它最多可以在测试时给您一个提示:godbolt.org/z/nHfIoN

标签: c compiler-warnings


【解决方案1】:

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

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

其他预防措施包括编码风格和命名约定:非常严格的风格规则,尤其是一致地使用空格和缩进,有助于使代码更具可读性,并减少隐藏愚蠢错误的空间。命名约定也有帮助:在您的示例中,不应将参数命名为 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(以及用于clang的-Weverything)之外,还有一些我用于项目的额外标志:

  • 避免与潜在签名char 相关的问题类型:-funsigned_char -Wchar-subscripts
  • 使用可变格式字符串阻止printf-Wformat-nonliteral
  • 制作字符串文字const: -Wwrite-strings

【讨论】:

    【解决方案2】:

    我的问题是如何才能最好地发现代码中的这些小错误?

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

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

    如果假设没有内存损坏,那么一些额外的代码分析器工具(如 f.e.)甚至都无法找到它。 AddressSanitizer 或 Valgrind。

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

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

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


    但要回答你的问题:

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

    例如 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

    【讨论】:

      【解决方案3】:

      编译器无法检查逻辑错误。你可能是故意写的。

      哦,要检查更多可自动检测的问题,GCC 知道-pedantic,但请阅读完整文档。您可能想尝试一下 clang 的功能。

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

      【讨论】:

        猜你喜欢
        • 2014-09-14
        • 2022-01-07
        • 1970-01-01
        • 2017-01-23
        • 2023-04-02
        • 1970-01-01
        • 2011-01-31
        • 2017-01-15
        • 2021-07-22
        相关资源
        最近更新 更多