6

为什么将函数强制转换为除了返回类型相同的函数类型失败?,我想更全面地了解函数类型和函数签名之间的区别。

例如,在处理函数指针时通常必须考虑函数的类型,函数的类型包括该函数的返回类型。

但是,正如 Mike Seymour 对上述问题的回答中所指出的,函数的签名与函数的类型不同。签名当然用于消除潜在的重载函数之间的歧义(注意函数的返回类型在识别唯一函数中不起作用)。但是,我现在想了解函数签名与函数类型的相关性和重要性。我突然想到,C++ 中函数签名的唯一目的是在重载决议期间识别重载候选者和/或重载集中的唯一函数。

我对么?重载解析是 C++ 中函数签名的唯一目的吗?或者,除了(或仅间接相关)重载解析之外,函数签名还有其他用途/应用吗?

附录为清楚起见,请注意,我特别想了解函数签名的目的和函数类型之间的区别。即,我知道函数类型对于函数指针的使用和编译器/链接器的调用约定实现都是必需的。但是,调用约定仅在重载决议完成后才相关。我在这里特别问,如果函数签名(与type相对)的唯一目的是用于重载解决方案。

4

2 回答 2

2

The standard mentions that signatures are used for name mangling and linking.

That being said, name mangling is not standarized. The return type is redundant in a function symbol (since there is only one possible return type for a function with a given name and arguments in a valid program, it is not required to differentiate two different symbols), but even then some ABIs do include the return type of a function in the mangled name, probably as a way of double checking that there is no violation of the rule above.

于 2012-12-03T16:42:39.417 回答
2

我对么?

就我而言,还有其他目的。考虑到 C 也有函数签名但没有重载。

除了重载之外,函数签名的基本目的是符合特定平台的调用约定。

当函数接受参数并返回值时,编译器需要知道参数的类型和大小才能正确地将它们传递给函数。通常,函数参数被压入堆栈(但这不是通用规则,尤其是在 64 位架构系统上)。考虑以下情况。如果你调用一个函数

foo(42);

编译器如何知道它必须传递给函数的整数值的大小?该数字42可以使用各种位宽表示,例如 1、2、4(甚至 8)字节整数:

00101010
0000000000101010
00000000000000000000000000101010

现在,如果函数没有签名说明,例如,参数是 a char(1 个字节)、a short(可能是 2 个字节)或 a(int可能是 4 个字节),那么编译器有无法确定正确的尺寸。这意味着如果它将任意数量的字节压入堆栈,但函数需要另一个大小,则会发生堆栈损坏。

另一个很好的例子是返回结构 ( struct)。通常,原始返回值(例如整数和浮点数)在寄存器中返回;这通常是EAXx86 上的寄存器。但是,如果想编写一个返回结构的函数怎么办?如果结构的整体大小太大以至于无法放入寄存器,则编译器必须生成将返回值推入堆栈的代码,而不是将其分配给寄存器。所以如果一个函数被定义为

int foo()
{
    return 1337;
}

或作为

struct bar {
    int a;
    char b[16];
    float x;
};

struct bar foo()
{
    struct bar ret;
    ret.a = 0;
    memcpy(&ret.b, "abcdefghijklmno", sizeof(ret.b));
    ret.x = 3.1415927;
    return ret;
}

将生成不同的程序集(和机器代码)——第一个返回整数的函数将使用EAX寄存器来存储返回值,但第二个调用必须使用堆栈。

于 2012-12-03T16:44:59.060 回答