下面的代码完美地计算了一个数字的阶乘。
#include <stdio.h>
long int f_fact(int i);
int main() {
int a;
long int factorial;
printf("Please enter a numbern");
scanf("%d", &a);
factorial = f_fact(a);
printf("The factorial is %ldn", 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 numbern");
scanf("%d", &a);
factorial = f_fact(a);
printf("The factorial is %ldn", 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: 0
和Warnings: 0
,也更难发现问题。有什么建议可以更好地解决bug吗?非常感谢。
编译器不能检查逻辑错误。你可能是故意写那条指示的。
哦,为了检查更多可自动检测的问题,GCC知道-pedantic
,但请阅读完整的文档。你可能想试试clang的功能。
这是单元测试发挥作用的领域。从一本好书开始,尝试一些框架,然后测试你的逻辑。
您已经知道并使用了-Wall -Wextra
,它可以与-Werror
一起完成,通过标记许多经典问题来检测潜在的错误。
虽然您可以添加更多的编译器选项来尝试检测其他问题,但很难检测逻辑错误。例如,如果设置了一个变量但没有使用,则可以检测到简单的拼写错误,但您的错误仍然会被忽视。
其他注意事项包括编码风格和命名约定:非常严格的风格规则,特别是空格和缩进的一致使用,有助于提高代码的可读性,减少愚蠢错误的隐藏空间。命名约定也有帮助:在您的示例中,不应将参数命名为i
,而应将其命名为n
。i
是索引变量的默认名称,正如您自己所经历的那样,因此正确命名参数可以有效地防止这种错误:
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
">我的问题是如何最好地发现代码中的这些小错误?">
不幸的是,无论是在GCC还是Clang中,都没有编译器选项来检测逻辑问题。
在可以插入相同类型对象的地方使用放错位置的对象对于编译器来说是不可能检测到的,因为这是逻辑问题。编译器只能检测语法问题。
如果没有内存被破坏,那么一些额外的代码分析器工具(如AddressSanitizer或Valgrind(甚至无法找到它。
要防止这种错误,你唯一能做的就是在编码时要小心。
避免复制&粘贴过于频繁,而是通过单独编写代码部分来获得清晰的焦点。
关于所提供的问题,请避免复制循环头或其部分,尤其是在嵌套循环内部。
但要回答您的问题:
除了-Wall和-Wextra,还有什么其他工具可以用来发现尽可能多的错误或警告?
例如,GCC有-Wpedantic
/-pedantic
、-Wall
和-Werror
。
你可以在这里找到它们和更多,列出了它们的相应解释:
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-选项
对于Clang,您有f.e.-Weverything
。您可以在此处找到诊断选项列表及其描述:
https://clang.llvm.org/docs/DiagnosticsReference.html