为什么缺少头文件却可以成功编译程序?
我在学习“strtok”函数时发现了一个奇怪的问题。 起初我在写demo程序时漏掉了一个头文件,如下:
/* strtok example */
#include <stdio.h>
//#include <string.h> // the header file I've missed at first
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
编译器没有给出任何错误信息,成功编译了程序。但运行时会导致分段错误。当我添加缺少的头文件时,一切都很顺利。
我的问题是为什么编译器没有诊断出第一次编译的任何错误。我在 Mac OS X 下用 gcc4.2.1 编译了它。
I found a weird problem when I was learning the "strtok" function.
At first I missed a header file when writing a demo program as follows:
/* strtok example */
#include <stdio.h>
//#include <string.h> // the header file I've missed at first
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
The compiler didn't give any error message and successfully compiled the program. But it lead to a segmentation fault when running. And when I added the missing header file, everything went well.
My question is why the compiler didn't diagnose any errors for the first compilation. I compiled it under Mac OS X with gcc4.2.1.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 C 中,函数可以没有原型(声明)。调用此类函数时不会进行参数转换。例如:
即使未声明
f
,也会使用参数(int)0
调用名为f
的函数。当f
的实际定义(在另一个.c
文件或库中)例如时,这会导致未定义的行为(...段错误...)。int f(char*)
或int f(long)
。这不是一个好的做法,但保留是为了向后兼容原始 C。当原型存在时,编译器会在调用站点自动将参数转换为所需的类型(可能会发出错误)。
PS:不要误会我认为
int
是默认值。编译器实际调用的内容完全取决于调用参数。例如。f(1.1)
将与void f(double)
匹配,f("string")
与f(char*)< 匹配/代码>。
In C, functions were allowed to have no prototypes (declarations). There would be no parameter conversions when calling such functions. Eg.:
would call a function named
f
with a parameter(int)0
even whenf
was not declared. This results in undefined behavior (...segfaults...) when the actual definition off
(in another.c
file, or in a library) was eg.int f(char*)
orint f(long)
. This is not good practice, but is retained for backwards compatibility with original C.When the prototype is present, the compiler would automatically convert parameter to required types (possibly issuing an error) at call site.
PS: don't get me wrong thinking
int
is the default. What the compiler actually calls is entirely dependent on the call parameters. Eg.f(1.1)
would match withvoid f(double)
,f("string")
withf(char*)
.因为您没有使用
-Wall - 进行编译韦斯特拉
。对于新编写的现代代码,您应该理所当然地这样做。Because you didn't compile with
-Wall -Wextra
. For newly-written modern code, you should be doing this as a matter of course.