【问题标题】:Why standard forbids sizeof to be applied to functions为什么标准禁止 sizeof 应用于函数
【发布时间】:2014-03-05 07:36:39
【问题描述】:

标准 C (ISO/IEC 9899:1999) 第 6.5.3.4 节说

sizeof 运算符不应应用于具有 函数类型或不完整类型

但是为什么? 使用readelf 检查可执行文件会发现函数大小在编译期间完全知道。

Symbol table '.symtab' contains 67 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
.......
    37: 0000000000400541    16 FUNC    LOCAL  DEFAULT   13 clean
.......
    46: 00000000004005f0     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
......
    49: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.2.5
    52: 00000000004005f4     0 FUNC    GLOBAL DEFAULT   14 _fini
    53: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
ed
    58: 0000000000400560   137 FUNC    GLOBAL DEFAULT   13 __libc_csu_init

    62: 000000000040052c    21 FUNC    GLOBAL DEFAULT   13 main

这里的大小0 属于共享库中的函数,例如puts@@GLIBC_2.2.5 函数。于是我查了libc的信息,这里有一段readelf -a /lib/x86_64-linux-gnu/libc.so.6输出与puts@@GLIBC_2.2.5相关

                          Size  Type 
  ...........   
  399: 0000000000070ec0   392 FUNC    WEAK   DEFAULT   12 puts@@GLIBC_2.2.5

它只是不必要的功能,还是违反了C 理念,或者有一些我看不到的技术问题?

【问题讨论】:

  • 如果函数被内联怎么办?如何计算它的大小?

标签: c sizeof


【解决方案1】:

我认为这是因为sizeof 仅对具有unsigned char [sizeof(type)] 表示形式的对象有意义。现在在 C 中,函数没有表示形式(没有从函数指针类型到数据指针类型的转换),因此您可以说 sizeof 没有有意义的用法。

【讨论】:

    【解决方案2】:

    使用 readelf 检查可执行文件会发现函数大小在编译期间完全知道。

    但是如果你在同一个系统上用不同的编译器编译你的代码,甚至用不同的优化选项编译你的代码,这个大小通常会发生变化。例如,如果你使用gcc,试着用@987654324编译你的代码@ 和gcc -O2,然后比较你的函数的代码大小。

    但是编译器所做的优化并不假设改变他们试图优化的代码的行为。而让一个表达式在不同的优化级别下具有不同的值是在改变代码的行为。

    汇编器和/或链接器也可以对编译器生成的汇编代码做一些优化或修改,从而改变一些函数的代码大小。

    另外,C不是函数式编程语言,函数不是一等对象,这意味着你不能将它存储到一个变量中,将它作为参数传递给另一个函数,等等,似乎没有意义获取函数的大小。

    【讨论】:

    • 这就是为什么我在编译期间检查函数大小是否已知。他们是众所周知的。如果在编译期间已知大小,sizeof 可以返回当前编译中函数的大小,具有当前优化级别。
    • 但是编译器所做的优化并不假设改变他们试图优化的代码的行为。而让一个表达式在不同的优化级别下具有不同的值是在改变代码的行为。
    • 编译器不知道函数的最后大小,因为它可能会在链接时进行更多优化
    • @LưuVĩnhPhúc 我不知道即使在链接时也进行了优化。感谢这一点。
    【解决方案3】:

    C 的要点是它对指令进行抽象,因此您不必处理程序的二进制表示。与汇编程序相比,这提供了许多优势——主要是提高了生产力、便携性。

    sizeof 功能并不是很有用,因为您无论如何都无法访问数据或复制数据等。系统可以将可执行内存标记为仅执行,因此需要您的 C 标准能够做这些事情无法在这样的系统上实现。

    而且编译会困难得多。在一切完成之后,它基本上需要一个单独的通道,以返回填充函数的大小。

    话虽如此,这将是一个非常棒的功能,您可以检查 if (sizeof(*function) == 0) 以查看它是否被内联,等等。但是,考虑到 c99 并没有真正在所有地方实现然而,我想说,即使在最好的情况下,它也不会在 2050 年之前随时可用。

    【讨论】:

    • 我认为它可能对不同的逆向工程任务有用,也可能对小型嵌入式系统有用。但这只是一种推测,实际上我从来不需要知道函数的大小。
    猜你喜欢
    • 2011-05-18
    • 1970-01-01
    • 2023-03-16
    • 2013-05-10
    • 2020-01-28
    • 2015-08-21
    • 2013-09-24
    • 2011-02-09
    • 2011-12-15
    相关资源
    最近更新 更多