【问题标题】:Why is the size of a function in C always 1 byte?为什么 C 中函数的大小总是 1 个字节?
【发布时间】:2026-01-04 07:15:02
【问题描述】:

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

【问题讨论】:

    标签: c function size sizeof


    【解决方案1】:

    这是违反约束的,您的编译器应该诊断它。如果它编译它尽管如此,你的程序有未定义的行为[感谢@Steve Jessop 对故障模式的澄清,请参阅@Michael Burr's answer 了解为什么一些编译器允许这样做]:来自 C11,6.5.3.4./1 :

    sizeof 运算符不得应用于具有函数类型的表达式

    【讨论】:

    • 这是一个约束,这意味着在符合标准的编译器中它被诊断出来。如果编译器仍然编译它(已经诊断它),那么行为是未定义的。如果编译器没有诊断它(例如 gcc 没有-pedantic),你有一个不符合标准的编译器并且每个程序都有未定义的行为。
    • 这种行为将它与 GNU C 扩展归为一类,但我不知道为什么有人想要这种行为,所以我不知道为什么 GNU 作者竭尽全力添加它。
    • @SteveJessop:请注意,即使-std=c11 也是如此,不是 gnu11。这是一个非常奇怪的编译器扩展。
    • 哦!我敢打赌,它是在函数指针上启用算术运算,就像sizeof(void) 在 GNU C 中为 1 一样。
    • 关于-std=c11:有人应该将-std=c* 选项参考广告标准。它们不启用一致性模式,它们只是禁用会阻止格式正确的程序编译的扩展(例如 typeof 是关键字,因为格式正确的 C 程序可以将其用作变量名,但 @987654330 @ 默认情况下会拒绝)。要另外禁用允许格式错误的程序通过未诊断的扩展,您需要-pedantic-pedantic-errors
    【解决方案2】:

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

    但是,作为 C 语言的扩展,GCC 允许对 void 指针和函数指针进行算术运算,这是通过将 void 或函数的大小视为 1 来完成的。因此,sizeof 运算符将评估为 1 用于 void 或带有 GCC 的函数。见http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

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

    【讨论】:

    • 你的逻辑有缺陷。 C 需要一些但不是所有 UB 的诊断消息。你不能仅仅因为有诊断就说某事已经定义了行为。
    • C 需要对所有违反约束的诊断(C99 或 C11 中的 5.1.1.3 诊断)。约束(C99/C11 中的 3.8)是“要解释语言元素的阐述的句法或语义限制”,这似乎是说不遵循约束的东西不能被解释.
    • 并且要清楚 - 违反约束不会导致未定义的行为。这是一个错误,就像语法错误一样。例如,该标准说,“如果违反了在约束之外出现的“应”或“不应”要求,则行为未定义”。如果违反约束会导致 UB,为什么标准只讨论不受约束的“shalls”和“shall nots”?
    • 除了sizeof 一个函数不是 UB(我之所以提到这一点只是因为其他答案说它是 UB)之外,我真的没有说明任何关于 UB 的任何内容。但也许我混淆了这一点,因为我构建句子的方式。要更清楚。 sizeof 一个函数不是 UB(正如几个答案所声称的)。这是违反约束的。因此,它需要诊断。 GCC 允许它作为扩展。
    • @KerrekSB:OP 没有得到诊断,因为他们可能正在使用 GCC,这允许将其用作 C 语言扩展。
    【解决方案3】:

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

    由此而来的俚语术语“鼻恶魔”表示编译器为响应未定义的构造而决定执行的任何操作。 1 是本例编译器的鼻恶魔。

    【讨论】:

    • @IlmariKaronen 我不得不承认,我对 C(和 C++)的大部分回答要么是基于通用语言不可知论原则,要么是类似的历史数据,这是有原因的。我的 C 经验本身就接近历史了 :)
    【解决方案4】:

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

    如果您想分析您的程序函数大小,请检查链接器映射,它可以在中间结果目录中找到(东西被编译成 .obj/.o 或生成的图像/可执行文件所在的位置)。有时可以选择是否生成此映射文件...它取决于编译器/链接器。

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

    【讨论】:

    • 什么样的说法是“它肯定可以也可以不可以”???这不就是真的吗?
    • @KerrekSB 是的,但在这里它可能会或可能不会做任何事情,并且仍然在规则范围内。确实,编译器可能会或可能不会拒绝编译int x = 1;,但对于符合标准的编译器,只允许其中一个。将sizeof() 应用于函数时,它可能会或可能不会返回设定值,或拒绝编译,或根据当时特定寄存器中的任何内容返回随机值。字面鼻恶魔不太可能,但在标准的字母范围内。
    • @kerrek 这可能是真的,也可能不是假的……看它是模糊不合逻辑的。
    • 如果您想知道指向函数的指针的大小,请将sizeof 应用于指向函数的指针。
    最近更新 更多