4

快速提问:

strlen[char*]无论我是否都完美地#include <string.h>工作

我从编译器得到的只是关于隐式声明的警告,但在功能上它按预期工作。

这是为什么?

4

7 回答 7

6

当您调用undefined behavior时,一种可能的行为是程序按照您的预期运行,一个是您的系统,并且使用您安装的库和系统软件的当前版本。这并不意味着可以这样做。实际上,正确的 C99 编译器不应允许隐式函数声明;它应该给你一个错误。

于 2011-04-27T14:58:57.083 回答
4

C 中的函数原型不是强制性的。它们对编译器是有用的指示,以便它可以对传递给它们的类型进行类型检查。如果您不包含string.h,则假定该函数具有默认签名,这就是您收到警告的原因。

于 2011-04-27T14:45:19.140 回答
3

如果在范围内没有原型的情况下调用函数,编译器将生成代码来调用函数,该函数接受传递的任何类型的参数并接受整数结果。如果参数与函数所期望的匹配,并且如果函数以调用代码可以处理的方式返回其结果(*),那么一切都会好起来的。原型设计的目的是确保尽可能将参数转换为预期的类型,如果无法转换,编译将失败。例如,如果一个非原型函数需要一个“long”类型的参数并且尝试传递一个“int”,则可能会发生以下任何情况:

  1. 该程序可能会彻底崩溃
  2. 事情可能会按预期工作
  3. 该函数可以像传递了一些任意不同的参数值一样执行
  4. 程序可能会继续运行,但使用任意值会破坏任何或所有程序变量。
  5. 计算机可能导致恶魔可能飞出程序员的鼻子

相比之下,如果函数是原型的,则编译器将保证在调用函数之前执行将“int”转换为“long”所需的任何操作。

最初构思 C 时,原型并不存在,程序员负责确保所有参数都以预期的精确类型传递。在实践中,确保所有函数参数始终是完全正确的类型是一件非常痛苦的事情(例如,当将值 5 传递给期望为 long 的函数时,必须将其写为“5L”或“(long)5” )。实际上,除了可变参数函数外,没有任何理由依赖隐式参数类型。

(*) 不正确的参数类型可能发生的任何事情都可能发生在不正确的返回类型上,除非函数预期返回“int”并且函数的实际返回值适合“int”,结果比使用不正确的参数类型时更可能是正确的。

(**) 我能想到的唯一例外情况是,如果一个人正在为一些真正的旧硬件进行编程,而该硬件无法使用原型感知编译器,或者如果一个人正在为代码高尔夫或类似比赛进行编程。后者我认为是解决难题而不是编程,而且我不知道人们有兴趣使用前一种条件适用的任何硬件。

于 2011-04-27T15:06:07.657 回答
1

因为它是声明,即等于所谓的“默认声明”。编译器期望任何未知函数返回 int 并期望在代码中首次使用函数时传递的参数。

于 2011-04-27T14:43:47.883 回答
1

通常这是因为您包含的另一个头文件也包含 string.h。显然,假设您不需要仅仅因为其他事情而包含某些东西是不好的做法,但它很可能是造成这种影响的原因。

于 2011-04-27T14:47:49.320 回答
0

我猜这是因为在 C 中 int 是从函数返回的默认数据类型。你能给出一个更完整的代码示例吗?

于 2011-04-27T14:45:00.147 回答
0

函数原型在包含文件中。因此,即使您不包含这些文件,int function_name();也会编写一个固定的原型。现在 的代码strlen()在运行时链接的库文件中,因此该函数提供正确的输出(仅当它是唯一具有固定原型的函数时int function_name();)。

于 2011-04-28T08:50:24.987 回答