我为一个大学项目编写了一些C代码,它在Ubuntu上运行没有问题,在那里我编写了所有代码。当它被标记时,老师说它没有产生任何输出。它仍然适用于我,但我怀疑老师在Windows上运行我的代码证明是正确的,当我在Windows上运行时发现我的代码坏了。我把问题解决了。它是以下内容:
我有char数组:
char grade[2];
然后它有另一个char数组(char grade_str[3]
)的内容,其中包含,例如" B3",复制到其中(我知道这是一个错误)
strcpy(grade, grade_str);
将字符串grade
(假设现在等于" B3")与满分等级的文件进行比较,以获得匹配(使用strcmp
)。除了在Windows上(确切地说是7),它永远不会匹配,因为grade
最终看起来像这样," B30~ $)",并添加了几个额外的随机字符。由于数组只有2个字节,所以不应该这样。我知道问题几乎可以肯定是由于我没有为字符串和空字节提供足够的空间,并且使用char grade[3];
确实解决了这种情况。
但是,我想知道为什么我在Windows或Ubuntu上进行编译时没有出现任何错误,为什么进一步说,它每次都在Ubuntu上运行完美,但从不在Windows上运行。从现在开始,我觉得我必须在Windows和Linux上检查我的代码...或者有没有办法确保编译器正确引发这些错误,某种超级警惕的模式?
使用的编译器:
答案 0 :(得分:3)
你必须明白它在Linux上实际上无法正常运行...它会在内存中读取,直到找到空字符为止。
所以也许在Linux中你很幸运,你的数组旁边的字节是零,而在Windows上你不幸运。
但是无论如何糟糕的编程,你应该总是有一个空终止的字符串,否则这会导致很难找到的错误......
为了给你一个不工作的例子,Ubuntu为你提供了一些存储变量的空间。所以你有一个或两个变量,比如你的数组。有一天你会添加另一个变量,Linux会在你的数组之后存储它。然后它可能会在你的程序开始工作,然后你将初始化你的新变量,然后当你访问你的数组时它会崩溃......
答案 1 :(得分:2)
对非NULL终止的字符串调用字符串函数为undefined behavior(“UB”)。 UB意味着不知道会发生什么。它可能有用,或者可能无效。在您的情况下,它适用于Linux,它不适用于Windows。一旦你有了UB,就无法预测会发生什么。
UB始终需要注意并注意C语言。语言不会阻止您做出导致UB的事情。你需要小心自己。像Clang和GCC这样的编译器可以帮助您检测它,但是没有任何保证。
答案 2 :(得分:1)
您可以使用clang的地址清理程序在运行时捕获此类错误。
假设你有错误的代码:
#include <string.h>
int main()
{
char grade[2];
char grade_str[] = "B0";
strcpy(grade, grade_str);
return 0;
}
您可以使用-fsanitize=address
编译它:
clang -fsanitize=address main.c
如果您运行程序,它将会破坏一些调试信息。
==19588==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd9bcf7422 at pc 0x455bc0 bp 0x7ffd9bcf7350 sp 0x7ffd9bcf6b08
WRITE of size 3 at 0x7ffd9bcf7422 thread T0
==19588==WARNING: Trying to symbolize code, but external symbolizer is not initialized!
#0 0x455bbf (/tmp/a.out+0x455bbf)
#1 0x47afd1 (/tmp/a.out+0x47afd1)
#2 0x7fa15d228ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#3 0x47ac3c (/tmp/a.out+0x47ac3c)
[... and so on]
中找到更多信息