为什么C中的函数大小总是1个字节?


87

当我们使用检查函数的大小时sizeof(),我们总是得到1个字节。这1个字节表示什么?

Answers:


80

这是一个约束违例,您的编译器应该对其进行诊断。如果仍然进行编译,则您的程序具有未定义的行为[感谢@Steve Jessop阐明了故障模式,有关某些编译器为何允许这样做的信息,请参见@Michael Burr的回答]:从C11,6.5.3.4./ 1:

sizeof操作者不得应用于具有功能类型的表达式


11
这是一个约束,这意味着在合格的编译器中会对其进行诊断。如果编译器仍然进行编译(已诊断),则行为是不确定的。如果编译器无法诊断(例如gcc不能没有诊断-pedantic),则说明您的编译器不合格,每个程序都有未定义的行为。
史蒂夫·杰索普

1
该行为将其与GNU C扩展归为同一类,但我不知道为什么有人想要该行为,因此我不知道GNU作者为什么不肯添加它。
史蒂夫·杰索普

1
@SteveJessop:请注意,即使使用-std=c11,也没有 gnu11。这是一个非常奇怪的编译器扩展。
Kerrek SB 2012年

6
哦!我敢打赌,它使在函数指针,即以同样的方式运算sizeof(void)在GNU C.为1
史蒂夫·杰索普

3
关于-std=c11:有人应该将-std=c*选项参考广告标准。他们不启用一致性模式,只是禁用了扩展,以防止格式正确的程序编译(例如,typeof作为关键字,因为格式良好的C程序可以将其用作变量名,但是gcc默认情况下会拒绝该扩展名))。要另外禁用允许格式错误的程序通过未经诊断的扩展,您需要-pedantic-pedantic-errors
史蒂夫·杰索普

56

这不是未定义的行为-C语言标准在将sizeof运算符与功能指示符(函数名称)一起使用时需要进行诊断,因为这对sizeof运算符是一种约束。

但是,作为C语言的扩展,GCC允许对void指针和函数指针进行算术运算,这是通过将avoid或函数的大小视为来完成的1。因此,该sizeof运营商将评估到1void或与海湾合作委员会的功能。参见http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

sizeof通过使用GCC的-pedantic-Wpointer-arith选项,可以使GCC在与这些操作数一起使用时发出警告。或将设为错误-Werror=pointer-arith


您的逻辑有缺陷。C需要某些但不是全部UB的诊断消息。您不能仅凭诊断就说明某些行为已定义行为。
MSalters 2012年

4
C要求对所有违反约束的情况进行诊断(5.1.1.3 C99或C11中的诊断)。约束(在C99 / C11中为3.8)是“语法或语义上的约束,通过这些约束可以解释语言元素的说明”,这似乎表示无法理解不遵循约束的内容。
Michael Burr 2012年

3
而且要明确-违反约束不会导致未定义的行为。这是一个错误,例如语法错误。例如,标准说:“如果违反了在约束之外出现的“应”或“不应当”的要求,则行为是不确定的。如果违反约束会导致UB,为什么标准只讨论这里没有约束的“应该”和“不应该”?
Michael Burr 2012年

3
除了sizeof功能不是UB之外,我实际上并未说明任何其他有关UB的信息(我之所以提到它,只是因为其他答案都说它是UB)。但是也许由于我构造句子的方式而使我感到困惑。更加清楚。sizeof一个功能不是UB(正如一些答案所声称的)。这是违反约束的。因此,它需要诊断。GCC允许它作为扩展。
Michael Burr 2012年

2
@KerrekSB:OP不能得到诊断,因为大概他们正在使用GCC,这允许将其用作C语言扩展。
Michael Burr 2012年

13

它表示编译器作者将值定为1,而不是让恶魔从你的鼻子上飞出来(实际上,这是另一种未定义的用法,sizeof它使我们获得了这样的表达:“ C编译器本身必须发出诊断信息,如果这是第一个要求,程序产生的诊断信息,然后它本身可能导致恶魔从您的鼻子上飞走(顺便说一句,它很可能是记录在案的诊断消息),就像它可能针对进一步违反语法规则或约束(或,因此,无论出于何种原因,它都会选择)。“ https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

因此,there语是“鼻恶魔”,是指编译器为响应未定义的构造而决定执行的操作。1是这种情况下此编译器的鼻恶魔。


@IlmariKaronen我必须承认,这是有原因的,我对C(和C ++)的大多数回答都基于与语言无关的一般原理或诸如此类的历史掘金。我的C经验本身就与历史有关:)
乔恩·汉纳

7

正如其他人指出的那样,sizeof()可以采用任何有效的标识符,但是它不会为函数名称返回有效的结果(说实话是正确的)。此外,它肯定会或可能不会导致“恶魔出鼻”综合症。

如果要分析程序功能的大小,请检查链接器映射,该链接器映射可在中间结果目录中找到(该目录将内容编译为.obj / .o或生成的图像/可执行文件所在的目录)。有时,有一个选项可以生成或不生成此映射文件……它取决于编译器/链接器。

如果您想要函数的指针大小,则它们的大小都是相同的,即cpu上寻址字的大小。


1
什么样的陈述是“它肯定会或可能不会” ????这不是真的吗?
Kerrek SB 2012年

@KerrekSB是的,但是在这里它可能会或可能不会做任何事情,并且仍然在规则之内。确实,编译器可以拒绝编译,也可以不拒绝编译,int x = 1;但是对于符合标准的编译器,只允许其中之一。随着sizeof()被应用到的功能,它可能会或可能不会返回设定值,或拒绝编译,或者返回基于在当时特定的寄存器无论是一个随机值。文字上的鼻恶魔是不太可能的,但是在标准之内。
乔恩·汉娜

@kerrek可能一无是处,也可能并非一无是处……将其视为模糊的,不合逻辑的。
jpinto3912 2012年

1
如果您想知道函数指针的大小,请将其应用于函数sizeof指针。
alexis 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.