为什么 strlen 函数在没有 #include的情况下也能工作?
快速问题:
无论我是否 #include
,strlen[char*]
都能完美工作。
我从编译器得到的只是有关隐式声明的警告,但是从功能上讲,它按预期工作。
这是为什么?
Quick question:
strlen[char*]
works perfectly regardless whether I #include <string.h>
or not
All I get from compiler is a warning about implicit declaration, but functionally it works as intended.
Why is that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
通常这是因为您包含的另一个头文件也包含 string.h。显然,仅仅因为其他东西需要包含某些内容就假设您不需要包含某些内容是不好的做法,但它很可能是造成这种效果的原因。
Usually this is because another header file which you have included ALSO includes string.h. Obviously it is bad practice to assume that you don't need to include something just because something else does, but it is most likely responsible for this effect.
我猜这是因为在 C 中 int 是从函数返回的默认数据类型。
你能给出更完整的代码示例吗?
I guessing it's because in C an int is the default data type returned from a function.
Can you give a fuller code example.
函数原型位于包含文件中。因此,即使您不包含这些文件,也会编写一个固定原型
int function_name();
。现在 strlen() 的代码位于运行时链接的库文件中,因此该函数给出正确的输出(仅当它是唯一具有固定原型的函数时) int function_name ();)。The function prototype is there in include files. So even if you don't include those files, a fixed prototype
int function_name();
is written. Now the code ofstrlen()
is there in the library files which are linked at run time, so the function gives correct output (only if it is the only function with a fixed prototypeint function_name();
).当您调用未定义的行为时,一种可能的行为是程序按照您的预期运行,在您的系统中,并且使用当前版本您已安装的库和系统软件。这并不意味着可以这样做。实际上,正确的 C99 编译器不应该允许隐式函数声明;它应该给你一个错误。
When you invoke undefined behavior, one possible behavior is that the program behaves as you expected it to, one your system, and with the current version of libraries and system software you have installed. This does not mean it's okay to do this. Actually a correct C99 compiler should not allow implicit function declarations; it should give you an error.
C 中的函数原型不是强制性的。它们对编译器来说是有用的指示,以便编译器可以对传递给它们的类型进行类型检查。当您不包含
string.h
时,将假定该函数使用默认签名,这就是您收到警告的原因。The function prototypes in C are not compulsory. They're useful indications to the compiler so that it can do type checking on types which are passed into them. When you don't include
string.h
, a default signature is assumed for the function which is why you get the warning.如果在作用域内没有原型的情况下调用函数,编译器将生成代码来调用函数,该函数接受传递的任何类型的参数并接受整数结果。如果参数与函数期望的参数匹配,并且函数以调用代码可以处理的方式返回其结果(*),那么一切都会好起来的。原型设计的目的是确保参数尽可能转换为预期类型,如果无法转换,编译将失败。例如,如果非原型函数需要“long”类型的参数,并且尝试传递“int”,则可能会发生以下任一情况:
相比之下,如果该函数是原型化的,则可以保证编译器在调用该函数之前执行任何必要的操作,将“int”转换为“long”。
当 C 最初构思时,原型并不存在,程序员负责确保所有参数都以预期的精确类型传递。在实践中,确保所有函数参数始终都是正确的类型是一件非常痛苦的事情(例如,当将值 5 传递给需要 long 的函数时,必须将其写为“5L”或“(long)5” )。实际上,除了可变参数函数之外,没有任何理由依赖隐式参数类型。
(*) 不正确的参数类型可能发生的任何情况都可能因不正确的返回类型而发生,除非函数预期返回“int”并且函数的实际返回值适合“int”,结果比使用不正确的参数类型更有可能是正确的。
(**) 我能想到的唯一例外是,如果一个人正在为一些非常旧的硬件进行编程,而无法使用原型感知编译器,或者如果一个人正在为代码高尔夫或类似的比赛进行编程。我认为后者是解决难题而不是编程,而且我不知道人们有兴趣使用任何适用前一种条件的硬件。
If a function is called without a prototype in scope, the compiler will generate code to call a function which accepts whatever types of parameters are passed and accept an integer result. If the parameters match those the function expects, and if the function returns its result in a way the calling code can handle(*), all will be well. The purpose of prototyping is to ensure that arguments get converted into expected types if possible, and that compilation will fail if they cannot be converted. For example, if a non-prototyped function expects an argument of type 'long' and one attempts to pass an 'int', any of the following may occur:
By contrast, if the function were prototyped, the compiler would be guaranteed to do whatever was necessary to convert the 'int' to a 'long' prior to calling the function.
When C was originally conceived, prototypes didn't exist, and the programmer was responsible for ensuring that all arguments were passed with the precise types expected. In practice, it's a real pain to ensure that all function arguments are always the exact proper types (e.g. when passing the value five to a function that expects a long, one must write it as either "5L" or "(long)5"). Realistically speaking, there's never(**) any reason to rely upon implicit argument types, except with variadic functions.
(*) Any of the things that can happen with incorrect parameter types can happen with incorrect return types, except when a function is expected to return 'int' and the actual return value of the function would fit in an 'int', the results are more likely to be correct than when incorrect parameter types are used.
(**) The only exceptions I can think of would be if one was programming for some really old hardware for which a prototype-aware compiler was unavailable, or if one was programming for a code-golf or similar competition. The latter I consider puzzle-solving rather than programming, and I'm unaware of any hardware people would be interested in using for which the former condition would apply.
因为它的声明等于所谓的“默认声明”。编译器期望任何未知函数返回 int 并期望在代码中第一次使用函数时传递的参数。
Because it's declaration ie equal to so called 'default declaration'. Compiler expects any unknown function to return int and expect parameters as passed at the first time of function usage in code.