C中的函数名是什么类型的?

时间:2013-09-15 20:00:30

标签: c function

我一直都明白,在C中,func&func是等价的。我假设它们都应该是类型指针,在我的Win64系统上是8个字节。但是,我只是尝试了这个:

#include <stdio.h>

int func(int x, int y)
{
    printf("hello\n");
}

int main()
{
    printf("%d, %d\n", sizeof(&func), sizeof(func));
    return 0;
}

预计得到输出8, 8会让8, 1感到惊讶。

这是为什么? func的确切类型是什么?它似乎是char或类似的类型 这是怎么回事?

如果它有所作为,我用gcc -std=c99编译了这个。

4 个答案:

答案 0 :(得分:37)

  

C中的函数名是什么类型的?

函数名称或函数指示符具有函数类型。当它在表达式中使用时,除非它是sizeof&运算符的操作数,它将从类型“函数返回类型”转换为类型“指向函数返回类型“。 (这在C99,6.3.2.1p4中规定)。

现在

sizeof(func)

无效C,因为函数类型的操作数不允许sizeof。这是在sizeof运算符的约束中指定的:

  

(C99,6.5.3.4p1约束)“sizeof运算符不应该应用于具有函数类型或不完整类型的表达式,这种类型的带括号的名称,或者指定位的表达式 - 现场成员。“

但是

sizeof(func)

GNU C中允许

GNU C中有一个允许它的GNU扩展,在GNU C sizeof中有一个函数类型的操作数,产生1

  

6.23关于void-和Function-Pointers的算法

     在void和函数类型上也允许使用

[...] sizeof,并返回1.

http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html

答案 1 :(得分:12)

假设:

int func(int x, int y) { /* ... */ }

表达式func是函数类型。具体来说,它的类型为int(int, int),这是C语法的类型“函数,其中两个int参数返回int。(您不会经常看到特定的语法,因为它不常见直接引用函数类型。)

大多数上下文中,函数类型的表达式被隐式转换为指向函数的指针;在这种情况下,指针的类型为int(*)(int, int)

隐式转换的上下文是:

  1. 当表达式是一元&的操作数时;在这种情况下,&func会产生函数的地址(就像func本身通常一样);以及

  2. 当表达式是sizeof的操作数时。如果没有此异常,sizeof func将产生函数指针的大小。相反,它是约束违规,需要编译器进行诊断。

  3. (旁注:当在函数调用中使用函数名时,会发生此转换。()“运算符”(标准不称之为)需要指向前缀的指针功能类型。)

    gcc恰好有非标准的扩展名;它允许对函数指针和类型void*进行指针运算,就像char*指针上的指针算术一样(即,它以字节为单位运算)。不幸的是,恕我直言,gcc通过kludge做到这一点,将函数类型和类型void的大小设置为1.这就是你获得sizeof func == 1的原因。如果您启用其中一种标准符合模式(例如gcc -std=c99 -pedantic),则会收到警告。

    顺便说一句,请勿使用%d打印sizeof的结果。 sizeof会产生size_t类型的结果。如果您的实现支持它(C99或更高版本),请使用%zu;如果没有,您需要使用强制转换将size_t值显式转换为可以打印的值。例如:

    printf("%lu\n", (unsigned long)sizeof &func);
    

答案 2 :(得分:5)

  

C中的函数名是什么类型的?

它是功能类型。

  

我一直都明白,在C中,func&func是等价的

嗯,它们不是“等同的”。但是,函数会衰减成指向函数的指针。

  

我认为它们都应该是类型指针

这是一个不正确的假设。

  

并且期望获得输出8,8但是惊讶地得到8,1。这是为什么?

因为1.如果它编译它是UB,2。它甚至不应该首先编译,因此,你的程序可以自由地做任何事情。

答案 3 :(得分:1)

名称在C中没有类型。某些名称表示具有类型的实体,例如typedef名称,对象或函数。其他类型的名称表示没有类型的实体,例如预处理程序符号或goto标签。然而,其他类型的名称只是简单地表示类型,即typedef名称。

函数的名称表示具有函数类型的实体。该函数类型包括返回类型和(可能不完整)有关参数的信息。

当函数用作值时,它们总是被操作为指针到函数类型。这样的函数不能在便携式C程序中传递,但是指向函数的指针可以是。

从概念上讲,即使在像foo()之类的直接调用中,也会发生foo,表示函数的表达式,在评估时被隐式转换为指向函数的值。然后()函数调用后缀运算符通过此指针调用该函数。

有一个规则,如果表达式是&(地址)或{{1}的操作数,则具有函数类型的表达式会生成指针值,外运算符。 sizeoffunc仅在它们产生相同值的意义上是等价的。 &func隐式生成指针值。 func禁止隐式生成指针(&funcfunc的操作数,因此转换被抑制),但随后&获取地址。

因此,您可以看到&sizeof &func不同。前者采用指针的大小,后者尝试采用函数的大小。

获取函数的大小是C中的约束违规:它需要来自符合标准的实现的诊断。如果程序仍在翻译并且在运行时生成sizeof func的值,则这是特定于您的语言实现的“奖励”行为。它不是标准语言。