【问题标题】:Why main() cannot be declared as a static in C?为什么 main() 不能在 C 中声明为静态的?
【发布时间】:2010-09-24 03:25:59
【问题描述】:

为什么 main 必须声明为好像它具有外部链接?

为什么它不应该是静态的?

外联是什么意思??

【问题讨论】:

    标签: c function static main


    【解决方案1】:

    因为您将启动文件链接到您的程序,该程序包含(通常)调用您的 main 的汇编代码。如果 main 是静态的,则该代码将无法调用 main。

    external linkage 表示其他所谓的translation-units 可以在自己的翻译单元中看到您声明为 extern 的符号。因此,您的 main 是 extern,并且它的翻译单元符号表中将有一个条目来说明其地址。然后,其他翻译单元将能够在他们想要调用 main 时跳转到该地址。

    static linkage 表示您的符号是严格的本地翻译单元。这意味着其他 translation units 将无法看到该符号。因此,具有静态链接的符号可以多次出现在不同的翻译单元中,并且它们不会相互冲突,因为它们是本地的。

    编辑:通常,编译器从翻译单元生成的文件特定于该特定编译器。对于 linux 上的 gcc,通常使用 ELF 对象格式。您可以使用readelf -sW <file>.o(下面的简单测试文件)查看其符号表:

    test.c

    void bar(void);
    
    static int foo(void) {
        return 1;
    }
    
    int main(void) {
        bar();
        return foo();
    }
    

    这是readelf的输出:

    Symbol table '.symtab' contains 10 entries:
       Num:    Value  Size Type    Bind   Vis      Ndx Name
         0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
         1: 00000000     0 FILE    LOCAL  DEFAULT  ABS test.c
         2: 00000000     0 SECTION LOCAL  DEFAULT    1
         3: 00000000     0 SECTION LOCAL  DEFAULT    3
         4: 00000000     0 SECTION LOCAL  DEFAULT    4
         5: 00000000    10 FUNC    LOCAL  DEFAULT    1 foo
         6: 00000000     0 SECTION LOCAL  DEFAULT    6
         7: 00000000     0 SECTION LOCAL  DEFAULT    5
         8: 0000000a    36 FUNC    GLOBAL DEFAULT    1 main
         9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND bar
    

    您会看到 main 函数和一个由 main 调用的静态 foo 函数。还有一个函数被调用,它没有在文件中定义,但在另一个目标文件中定义。由于目标文件尚未最终链接,因此尚未为函数分配最终地址。在最终链接之后,这些将被安排到可执行文件中并分配地址。目标文件具有调用尚未定义函数的条目,因此当链接文件时,这些调用指令可以存储最终地址 (readelf -r <file>.o):

    Relocation section '.rel.text' at offset 0x308 contains 1 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    0000001c  00000902 R_386_PC32        00000000   bar
    

    【讨论】:

    • 我们如何分析那些翻译单元。我们能以表格或图形形式为每个文件查看它们吗?如果不可能,那么我们可以在哪个编译器生成的文件或属性文件中知道属性一个函数。?
    • 您的工具供应商将拥有执行此操作的实用程序。例如。 objdump (Unixy)、dumpbin (MSFT)、tdump (Borland/CodeGear/Embarcadero)
    • 好的好的,谢谢你们的解释。这对我有很大帮助
    • 很棒的答案。非常喜欢
    • 还有 'nm' 用于 Unix。 'objdump' 更强大,但你需要了解选项。
    【解决方案2】:

    代码的真正起点隐藏在 C 运行时库中。此运行时库调用您的 main() 例程。为了让链接器将 C RTL 调用与您的 main() 函数连接起来,它需要在文件外部可见。

    外部链接就是这样:这意味着有问题的名称作为目标文件导出的一部分是可见的。链接器的工作是连接所有的导入和导出,这样就没有未完成的导入。

    【讨论】:

      猜你喜欢
      • 2014-05-12
      • 2013-08-01
      • 2011-04-04
      • 2014-11-09
      • 2016-11-22
      • 2011-01-23
      • 2011-10-13
      • 2010-09-19
      相关资源
      最近更新 更多