【问题标题】:consequences of calling a function with fewer arguments in C?在 C 中调用具有较少参数的函数的后果?
【发布时间】:2014-05-23 16:03:23
【问题描述】:

我写了一个函数,它接受一些参数和一个指针参数。调用函数时,有时我需要传递指针以在函数内部使用,有时我不需要。 用更少的参数调用函数的后果是什么?它可以正确编译,并且在运行时仍然可以,但是这是好的编程吗?如果我用虚拟变量调用函数会更好吗? 感谢和抱歉初学者的问题。

【问题讨论】:

  • 将 NULL 传递给“未使用的参数”不是一个选项吗?
  • 这肯定不是好的编程。即使它编译,它也必须抛出警告。函数调用必须匹配其原型,该原型必须匹配其定义签名。
  • 打开所有警告。非常注意他们。
  • 如果你的函数需要三个参数并且你用两个参数调用它,你会调用未定义的行为,这是要不惜一切代价避免的,因为当你调用未定义的行为时编译器可以让你的程序做任何事情。不要冒险;始终传递完整的参数,即使它们为 NULL。如果它编译正确,则说明您没有正确使用 C 或您的编译器。
  • @user3668489 : 你能把代码粘贴到你的问题中,这样每个人都可以停止猜测,看看到底发生了什么?

标签: c function arguments call


【解决方案1】:

如果你调用一个参数太少的函数并且编译器没有抱怨,那么你做错了。

可以编写一个不指定它需要多少参数的函数声明/定义:

void func();
/* ... */
func();
func(arg1);
func(arg1, arg2);

这三个调用都会被编译器接受,但至少有两个是不正确的。

自 1989 年 ANSI C 标准以来,这种形式的函数声明/定义已过时

永远不要使用这种形式。

函数声明应该总是写成原型,即指定参数数量和类型的声明。作为特例,(void) 表示没有参数的函数。

void func(int arg);
/* ... */
func();           /* rejected by compiler */
func(arg1);       /* accepted -- but only if arg1 is of type int or convertible to int */
func(arg1, arg2); /* rejected by compiler */

如果您编写的代码调用带有错误数量参数的函数并使其通过编译器,则行为未定义。它可能看起来“有效”,但是当您使用不同的编译器或使用相同的编译器和不同的选项编译它时,它可能会在您面前爆炸。

一个复杂的问题:一些函数是可变参数,接受可变数量的参数。最常见的例子是printf。对于可变参数函数,所需的参数通常由函数的文档指定 - 正确获取参数同样重要。不同之处在于,对于可变参数函数,您的编译器不一定会告诉您调用不正确。

, ... 语法(在函数声明中)和<stdarg.h> 中定义的宏是唯一编写和使用采用变量编号和类型的 C 函数的合法方式论据。

【讨论】:

  • “编译器不抱怨” - 你的意思是在编译时显示警告还是错误?我只收到一个警告(不小心调用了一个太多的参数),这是否意味着我在 .h 文件中的原型不可见?
  • @RoG:C 标准只需要“诊断消息”来说明违反语法规则或约束的情况。一个非致命警告就足够了,许多 C 编译器会针对许多违规情况打印警告。认真对待警告。
【解决方案2】:

C++ 与普通 C 的区别之一是它包含 name mangling,它允许您指定具有不同返回类型和参数的单个函数。两个同名但参数不同的函数:

int foo();
int foo(int param1, char* param2);

可以在 C++ 中完成,因为它实际上在编译时会在后台更改函数的名称。当你想传入不同数量的参数时,它本质上与调用两个不同的函数名相同:

int foo1();
int foo2(int param1, char* param2);

当你传入的参数少于预期时,一些编译器至少应该抛出警告;其他人甚至根本不会编译程序。

假设您将 2 个参数传递给期望为 3 的函数。当您尝试在函数中引用该第 3 个参数时,您期望该值是多少?大多数情况下,这将是一个垃圾值,而且绝对是您的函数所不期望的。

我建议只将一个虚拟值传递给类似的函数:NULL 用于指针或0 或负“未初始化”类型的值用于其他类型。您至少可以在函数中测试这些值。或者只是编写第二个接受不同数量参数的函数。

【讨论】:

  • 如果我传递一个 NULL 指针,这是否也会产生任何后果?我的程序仍然可以正常工作。
  • 如果您在尝试访问指针之前检查NULL,则不会。但通常以指针为预期值或NULL 的方式编写它更安全,不会让杂散的“垃圾值”泄漏到其中并给您带来不可预测的结果。
【解决方案3】:

我不会这样做。我只会用声明的参数数量调用函数。

代码的读者非常困惑。

代码的读者甚至可能认为该函数已重载并查看 用于具有较少参数的函数的其他定义。

省略的参数可以有任何值——任何东西都被 C 编译器认为是合法的行为。该程序可能在测试环境中完美运行,然后由于任何原因或没有原因崩溃。

如果我绝对必须有可变数量的参数,出于合法目的,我会尝试将参数放在一个列表中,而不是使用可变数量的参数。如果其他人要求我使用可变参数,我将使用可变参数而不是默认行为,并且仅在所有参数都是相同类型的情况下使用。

【讨论】:

  • printf 接受可变数量的参数,通常是不同的类型。只要可变参数函数有足够的信息来知道会发生什么(在printf 的情况下,该信息在格式字符串中),并且只要调用是正确的,就不会有问题。但是, ... 语法和<stdarg.h> 是编写和使用接受可变数量和类型参数的 C 函数的唯一方法。
  • 是的,printf 有效;据我所知,编译器无法检测传递给 printf 的类型在编译时是否有效——这是我一直试图避免的风险。
猜你喜欢
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多