下面的代码完美地计算了一个数字的阶乘。
#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: 0
和... Warnings: 0
这就更难发现问题了。有什么建议可以让我更好的解决bug吗?谢谢您
你已经知道并使用 -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
(和 -Weverything
为clang)。)
char
型。 -funsigned_char -Wchar-subscripts
printf
与可变格式字符串。-Wformat-nonliteral
const
: -Wwrite-strings
一个编译器 不能 检查逻辑错误。你可能是特意写的那条指令。
哦,再检查几个可自动检测的问题,GCC知道了 -pedantic
但请阅读完整的文档。你可能会喜欢尝试clang的功能。
这是单元测试发挥作用的领域。从一本好书开始,尝试一些框架,然后测试你的逻辑。
"我的问题是,如何才能最好地发现代码中的这些小错误?"
不幸的是,没有任何编译器选项可以检测到 合理的 问题,无论是在GCC还是Clang中。
在可以插入相同类型对象的地方使用一个错位的对象是不可能被编译器检测到的,因为这是一个 合理的 问题。编译器只能检测到 句法 的问题,如果没有内存损坏,甚至无法通过一些额外的代码分析工具(如Address Sanitizer或Valgrind)发现。
如果没有内存损坏,甚至无法通过一些额外的代码分析工具如AddressSanitizer或Valgrind发现。
你唯一能做的就是要小心编码,避免出现这样的错误。
避免过于频繁地复制& 粘贴,而是通过单独编写代码部分来明确重点。
关于提供的问题,避免复制循环头或部分循环头,尤其是嵌套循环内部。
但要回答你的问题。
除了-Wall和-Wextra还有什么工具可以发现尽可能多的错误或警告?
有以下几个工具 -Wpedantic
-pedantic
, -Wall
和 -Werror
例如,GCC的。
你可以在这里找到它们和更多的相关解释。
https:/gcc.gnu.orgonlinedocsgccWarning-Options.html#Warning-Options。
对于Clang,你有f.e. -Weverything
. 你可以在这里找到诊断选项的列表和描述。