【问题标题】:calling function with lesser number of arguments in C?在C中调用具有较少参数的函数?
【发布时间】:2015-08-01 11:48:47
【问题描述】:

我奇怪地发现 C 允许链接参数列表不匹配的函数:

//add.c
int add(int a, int b, int c) {
    return a + b + c;
}
//file.c
int add (int,int); //Note: only 2 arguments
void foo() {
    add(1,2);
}

我先编译add.c,再编译file.c,都编译成功。奇怪的是,链接器没有给出任何错误或警告,可能原因是 C 链接器在链接时不比较参数。不过,我不是 100% 确定的。请有人对此发表评论。

现在,问题是避免这种情况或在编译期间获得某种警告的好习惯是什么,因为在我的项目中,不同文件中有很多函数,现在我们必须添加一些额外的参数在函数中。

【问题讨论】:

  • 函数将像拥有所有参数一样运行,但第三个参数可能只是垃圾并导致UB
  • @Dayalrai:不-这是未定义的行为-几乎任何事情都可能发生。在许多 ABI 上,堆栈帧将不正确,从而导致潜在的灾难性后果。
  • 您有一个双重且不一致的声明。声明仅在编译时有用,因此编译器可以检查函数是否正确使用。如果您设法像以前那样欺骗编译器,链接器只会找到对add() 的调用和add() 的代码并将它们链接在一起。
  • 正确的做法是拥有一个包含文件,该文件公开 C 文件中的原型(函数声明)。如果你有 add.c 你必须有 add.h 其中 add.c 的函数被声明为原型......这种行为允许你避免你指出的问题。您可以使用gcc -Wall 来验证所有警告,选项--pedantic 表示更多警告(但很无聊)
  • 我不想卷入一场投票战,但我投了赞成票,因为这是一个完全合理的问题,可以提高对“C”的理解。

标签: c arguments argument-passing


【解决方案1】:

正确使用您的头文件。
配置您的编译器以发出尽可能多的警告。
注意警告!

add.h

#ifndef ADD_H_INCLUDED
#define ADD_H_INCLUDED
int add(int a, int b, int c);
#endif

add.c

#include "add.h"
int add(int a, int b, int c) {
    return a + b + c;
}

file.c

#include "add.h"
void foo() {
    add(1, 2);
}

【讨论】:

    【解决方案2】:

    C 链接器在链接时不比较参数。

    没错。与将参数类型视为函数签名的一部分的 C++ 链接器不同,C 链接器仅考虑函数名称。这就是为什么可以简单地通过提供错误的函数原型来创建具有未定义行为的情况。

    有什么好的做法可以避免这种情况或在编译期间收到某种警告?

    始终将您打算共享的函数原型放入标头中,并从使用该函数的位置和定义该函数的位置包含该标头。这将确保编译器发出诊断消息。将所有编译器警告视为错误。 C 编译器通常比较宽容,因此它们的警告通常表明一些非常重要的事情。

    【讨论】:

      【解决方案3】:

      调用带有少量参数的函数会导致undefined behavior,因为这些参数的值是不确定的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多