我一直都明白,在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
编译了这个。
答案 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扩展,在GNU C sizeof
中有一个函数类型的操作数,产生1
:
6.23关于void-和Function-Pointers的算法
在void和函数类型上也允许使用[...] sizeof,并返回1.
答案 1 :(得分:12)
假设:
int func(int x, int y) { /* ... */ }
表达式func
是函数类型。具体来说,它的类型为int(int, int)
,这是C语法的类型“函数,其中两个int
参数返回int
。(您不会经常看到特定的语法,因为它不常见直接引用函数类型。)
在大多数上下文中,函数类型的表达式被隐式转换为指向函数的指针;在这种情况下,指针的类型为int(*)(int, int)
。
隐式转换不的上下文是:
当表达式是一元&
的操作数时;在这种情况下,&func
会产生函数的地址(就像func
本身通常一样);以及
当表达式是sizeof
的操作数时。如果没有此异常,sizeof func
将产生函数指针的大小。相反,它是约束违规,需要编译器进行诊断。
(旁注:当在函数调用中使用函数名时,会发生此转换。()
“运算符”(标准不称之为)需要指向前缀的指针功能类型。)
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}的操作数,则具有函数类型的表达式会生成指针值,除外运算符。 sizeof
和func
仅在它们产生相同值的意义上是等价的。 &func
隐式生成指针值。 func
禁止隐式生成指针(&func
是func
的操作数,因此转换被抑制),但随后&
获取地址。
因此,您可以看到&
和sizeof &func
不同。前者采用指针的大小,后者尝试采用函数的大小。
获取函数的大小是C中的约束违规:它需要来自符合标准的实现的诊断。如果程序仍在翻译并且在运行时生成sizeof func
的值,则这是特定于您的语言实现的“奖励”行为。它不是标准语言。