【问题标题】:In C, main need not be a function?在 C 中,main 不需要是一个函数吗?
【发布时间】:2011-01-16 04:19:06
【问题描述】:

这段代码可以编译,但并不奇怪,它在链接时失败(没有找到 main):

清单 1:

void main();

链接错误:\mingw\lib\libmingw32.a(main.o):main.c:(.text+0x106) undefined reference to _WinMain@16'

但是,下面的代码可以正常编译和链接,但有一个警告:

清单 2:

void (*main)();

警告:'main' 通常是一个函数

问题:

  1. 在清单 1 中,链接器应具有 抱怨缺少“主要”。为什么 它在寻找 _WinMain@16 吗?

  2. 生成的可执行文件 清单 2 简直崩溃了。什么是 原因?

感谢您的宝贵时间。

【问题讨论】:

  • 它崩溃是因为取消引用 void (*main)(); 会执行一个 NULL 指针(如果那是您的完整代码)

标签: c main


【解决方案1】:

没错,main 不需要是函数。这已在一些混淆程序中被利用,这些程序在一个名为main 的数组中包含二进制程序代码。

main() 的返回类型必须是int(不是void)。如果链接器正在寻找WinMain,它认为您有一个GUI 应用程序。

【讨论】:

    【解决方案2】:

    在大多数 C 编译系统中,没有与链接符号相关的类型信息。您可以将 main 声明为例如:

    char main[10];
    

    链接器会非常高兴。如您所述,除非您巧妙地初始化了数组的内容,否则程序可能会崩溃。

    您的第一个示例没有定义 main,它只是声明它,因此出现链接器错误。

    第二个例子定义了main,但是不正确。

    【讨论】:

    • > 第二个示例定义了 main,但不正确。这是否意味着编译器为此代码分配了一些存储空间? void (*main)(); 这不只是一个声明,main 指向一个函数,它接受未指定数量的参数并且什么都不返回? (相对于定义)?
    • 帖子+1。您能否举一个声明为数组的 main 示例并且代码可以工作?我很想知道这一点。从来没有遇到过这样的代码。
    • 在过去,做这样的事情更容易。有关可执行数组的示例,请参阅stackoverflow.com/questions/2251859/…
    • int main[] = { 0xC3 }; 0x63 是 RET(返回)的操作码。令人惊讶的是,这似乎返回 1!不知道这个 1 来自哪里。 ;)
    【解决方案3】:

    案例 1. 是特定于 Windows 的 - 当正确定义 main 时,编译器可能会生成 _WinMain 符号。

    案例 2. - 你有一个指针,但作为静态变量 它被初始化为零,因此崩溃了。

    【讨论】:

    • 编译器在开发windows应用程序时通常需要'_WinMain'。许多编译器都有一个 console 模板,它需要 main,但不提供所有的窗口功能,只是老式的 C。
    • Thomas,谢谢,我知道的就这么多。只是不确定 VS 是否会自动“植入”_WinMain 到控制台程序中。
    【解决方案4】:

    在 Windows 平台上,如果您不将程序设置为控制台应用程序,则程序的主要单元是 WinMain。 “@16”表示它需要 16 个字节的参数。所以只要你给它一个名为 WinMain 的函数,它有 16 个字节的参数,链接器就会很高兴。

    如果您想要控制台应用程序,这表明您搞砸了。

    【讨论】:

      【解决方案5】:

      您声明了一个名为 main 的指向函数的指针,链接器警告您这不起作用。

      _WinMain 消息与 Windows 程序的工作方式有关。在 C 运行时级别之下,Windows 可执行文件有一个 WinMain。

      【讨论】:

        【解决方案6】:

        尝试将其重新定义为int main(int argc, char *argv[])

        您所拥有的是链接器错误。链接器希望找到具有该“签名”的函数 - 不带参数的无效

        http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html

        【讨论】:

        • 函数 main 不需要有参数。 int main(void) 也是一个完全有效的签名。但是,在 C 中(与 C++ 不同) int main() 意味着它可以接受任何参数,这是不好的风格,但 AFAIK 仍然合法。
        • 同意(抱歉)见en.wikipedia.org/wiki/… 但是,无论如何,他显然有一个链接器错误,因为没有声明主函数(同意?)。某些环境(尤其是那些用于开发基于 GUI 的程序的环境)会自动提供此功能。
        【解决方案7】:

        在清单 1 中,您是在说“我的代码中的其他地方定义了一个 main() --- 我保证!”。这就是它编译的原因。但是您躺在那里,这就是链接失败的原因。您收到缺少 WinMain16 错误的原因是因为标准库(用于 Microsoft 编译器)包含 main() 的定义,该定义调用 WinMain()。在 Win32 程序中,您将定义 WinMain(),链接器将使用 main() 的库版本来调用 WinMain()。

        在清单 2 中,您定义了一个名为 main 的符号,因此编译器和链接器都很高兴,但启动代码将尝试调用位于“main”位置的函数,并发现实际上没有函数在那里,然后崩溃。

        【讨论】:

        • 这是否意味着编译器为此代码分配了一些存储空间? void (*main)(); 这不只是一个声明,main 指向一个函数,它接受未指定数量的参数并且什么都不返回吗? (相对于定义)?
        • 没有。它为一个 pointer 分配空间给一个函数,该函数接受未指定数量的参数并且不返回任何内容。 char* main; 甚至 void *main; 也会完成同样的事情。
        【解决方案8】:

        1.) 在执行 main 中的代码之前调用(编译器/平台)相关函数,因此您的行为(_init 在 linux/glibc 的情况下)。
        2) 第二种情况的代码崩溃是合理的,因为系统无法将符号main 的内容作为一个函数访问,该函数实际上是一个指向任意位置的函数指针。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-11
          • 2011-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-22
          • 1970-01-01
          相关资源
          最近更新 更多