在 C++ 中,main 函数是编程的入口点,我如何将其更改为其他函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3974796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:10:41  来源:igfitidea点击:

in c++ main function is the entry point to program how i can change it to an other function?

c++cmain

提问by Badr

I was asked an interview question to change the entry point of a C or C++ program from main()to any other function. How is it possible?

我被问到一个面试问题,将 C 或 C++ 程序的入口点从main()任何其他函数更改为任何其他函数。这怎么可能?

回答by paxdiablo

In standard C (and, I believe, C++ as well), you can't, at least not for a hosted environment (but see below). The standard specifies that the starting point for the C code is main. The standard (c99) doesn't leave much scope for argument:

在标准 C(我相信,还有 C++)中,你不能,至少在托管环境中不能(但见下文)。该标准规定 C 代码的起点是main. 标准 (c99) 没有留下太多争论的余地:

5.1.2.2.1 Program startup: (1) The function called at program startup is named main.

5.1.2.2.1 程序启动: (1) 程序启动时调用的函数名为main。

That's it. It then waffles on a bit about parameters and return values but there's really no leeway there for changing the name.

就是这样。然后它对参数和返回值有点犹豫,但实际上没有改变名称的余地。

That's for a hosted environment. The standard also allows for a freestanding environment (i.e., no OS, for things like embedded systems). For a freestanding environment:

这适用于托管环境。该标准还允许独立的环境(即,对于嵌入式系统之类的东西,没有操作系统)。对于独立环境:

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined. Any library facilities available to a freestanding program, other than the minimal set required by clause 4, are implementation-defined.

在独立环境中(在这种环境中,C 程序可以在没有任何操作系统优势的情况下执行),程序启动时调用的函数的名称和类型是实现定义的。除了第 4 条要求的最小集合之外,任何独立程序可用的库设施都是实现定义的。

You can use "trickery" in C implementationsso that you can make it look like mainisn't the entry point. This is in fact what early Windows compliers did to mark WinMainas the start point.

您可以在 C实现中使用“诡计”,这样您就可以使它看起来main不是入口点。这实际上是早期 Windows 编译器所做的标记WinMain为起点。



First way: a linker may include some pre-main startup code in a file like start.oand it is this piece of code which runs to set up the C environment then call main. There's nothing to stop you replacing that with something that calls bobinstead.

第一种方式:链接器可能在一个文件中包含一些预主启动代码,start.o并且正是这段代码运行以设置 C 环境,然后调用main. 没有什么可以阻止你用调用的东西bob代替它。



Second way: some linkers provide that very option with a command-line switch so that you can change it without recompiling the startup code.

第二种方式:一些链接器提供了带有命令行开关的选项,这样您就可以在不重新编译启动代码的情况下更改它。



Third way: you can link with this piece of code:

第三种方式:你可以链接这段代码:

int main (int c, char *v[]) { return bob (c, v); }

and then your entry point for yourcode is seemingly bobrather than main.

然后你代码的入口点似乎bob不是main.



However, all this, while of possibly academic interest, doesn't change the fact that I can't think of one single solitary situation in my many decades of cutting code, where this would be either necessary or desirable.

然而,所有这一切,虽然可能具有学术兴趣,但并没有改变这样一个事实,即在我几十年的代码切割过程中,我想不出一个单独的情况,这是必要的或可取的。

I would be asking the interviewer: why would you wantto do this?

我会问面试官:你为什么这么做?

回答by Lefteris E

The entry point is actually the _startfunction (implemented in crt1.o) .

入口点实际上是_start函数(在crt1.o 中实现)。

The _startfunction prepares the command line arguments and then calls main(int argc,char* argv[], char* env[]), you can change the entry point from _startto mystartby setting a linker parameter:

_start函数准备的命令行参数,然后调用main(int argc,char* argv[], char* env[]),您可以从入口点改_startmystart通过设置连接参数:

g++ file.o -Wl,-emystart -o runme

Of course, this is a replacement for the entry point _startso you won't get the command line arguments:

当然,这是入口点的替代品,_start因此您不会获得命令行参数:

void mystart(){

}

Note that global/static variables that have constructors or destructors must be initialized at the beginning of the application and destroyed at the end. Keep that in mind if you are planning on bypassing the default entry point which does it automatically.

请注意,具有构造函数或析构函数的全局/静态变量必须在应用程序开始时初始化并在结束时销毁。如果您打算绕过自动执行的默认入口点,请记住这一点。

回答by liaK

From C++ standard docs 3.6.1 Main Function,

来自 C++ 标准文档3.6.1 Main Function

A program shall contain a global function called main, which is the designated start of the program. It is implementation-definedwhether a program in a freestanding environment is required to define a main function.

程序应包含一个名为 main 的全局函数,它是程序的指定开始。它是实现定义在独立环境中的程序是否需要定义一个主要功能。

So, it does dependon your compiler/linker...

因此,它确实取决于您的编译器/链接器...

回答by Chubsdad

If you are on VS2010, thiscould give you some idea

如果您使用的是 VS2010,可能会给您一些想法

As it is easy to understand, this is not mandated by the C++ standard and falls in the domain of 'implemenation specific behavior'.

很容易理解,这不是 C++ 标准规定的,而是属于“实现特定行为”的范畴。

回答by lorro

This is highly speculative, but you might have a static initializer instead of main:

这是高度推测性的,但您可能有一个静态初始值设定项而不是 main:

#include <iostream>

int mymain()
{
    std::cout << "mymain";
    exit(0);
}

static int sRetVal = mymain();

int main()
{
    std::cout << "never get here";
}

You might even make it 'Java-like', by putting the stuff in a constructor:

您甚至可以通过将这些内容放在构造函数中来使其“类似于 Java”:

#include <iostream>

class MyApplication
{
public:
    MyApplication()
    {
        std::cout << "mymain";
        exit(0);
    }
};

static MyApplication sMyApplication;

int main()
{
    std::cout << "never get here";
}

Now. The interviewer might have thought about these, but I'd personally never use them. The reasons are:

现在。面试官可能考虑过这些,但我个人从不使用它们。原因是:

  • It's non-conventional. People won't understand it, it's nontrivial to find the entry point.
  • Static initialization order is nondeterministic. Put in another static variable and you'll never now if it gets initialized.
  • 这是非常规的。人们不会理解它,找到切入点并非易事。
  • 静态初始化顺序是不确定的。放入另一个静态变量,如果它被初始化,你现在永远不会。

That said, I've seen it being used in production instead of init()for library initializers. The caveat is, on windows, (from experience) your statics in a DLL might or might not get initialized based on usage.

也就是说,我已经看到它被用于生产而不是init()用于库初始值设定项。需要注意的是,在 Windows 上,(根据经验)您在 DLL 中的静态可能会或可能不会根据使用情况进行初始化。

回答by Galaxy

With gcc, declare the function with attribute((constructor)) and gcc will execute this function before any other code including main.

使用gcc,用attribute((constructor)) 声明函数,gcc 将在包括main 在内的任何其他代码之前执行此函数。

回答by Ignacio Vazquez-Abrams

Modify the crt object that actually calls the main()function, or provide your own (don't forget to disable linking of the normal one).

修改实际调用该main()函数的 crt 对象,或提供您自己的(不要忘记禁用正常的链接)。

回答by shuva

I think it is easy to remove the undesired main() symbol from the object before linking.

我认为在链接之前很容易从对象中删除不需要的 main() 符号。

Unfortunately the entry point option for g++ is not working for me(the binary crashes before entering the entry point). So I strip undesired entry-point from object file.

不幸的是,g++ 的入口点选项对我不起作用(二进制文件在进入入口点之前崩溃了)。所以我从目标文件中删除了不需要的入口点。

Suppose we have two sources that contain entry point function.

假设我们有两个包含入口点函数的源。

  1. target.c contains the main() we do not want.
  2. our_code.c contains the testmain() we want to be the entry point.
  1. target.c 包含我们不想要的 main()。
  2. our_code.c 包含我们想要作为入口点的 testmain()。

After compiling(g++ -c option) we can get the following object files.

编译(g++ -c 选项)后,我们可以获得以下目标文件。

  1. target.o, that contains the main() we do not want.
  2. our_code.o that contains the testmain() we want to be the entry point.
  1. target.o,包含我们不想要的 main()。
  2. our_code.o 包含我们想要作为入口点的 testmain()。

So we can use the objcopy to strip undesired main() function.

所以我们可以使用 objcopy 去除不需要的 main() 函数。

objcopy --strip-symbol=main target.o

objcopy --strip-symbol=main target.o

We can redefine testmain() to main() using objcopy too.

我们也可以使用 objcopy 将 testmain() 重新定义为 main()。

objcopy --redefine-sym testmain=main our_code.o

objcopy --redefine-sym testmain=main our_code.o

And then we can link both of them into binary.

然后我们可以将它们都链接成二进制文件。

g++ target.o our_code.o -o our_binary.bin

g++ target.o our_code.o -o our_binary.bin

This works for me. Now when we run our_binary.binthe entry point is our_code.o:main()symbol which refers to our_code.c::testmain()function.

这对我有用。现在,当我们运行时our_binary.bin,入口点是our_code.o:main()our_code.c::testmain()函数的符号。

回答by Amir Zadeh

For Solaris Based Systems I have found this. You can use the .initsection for every platforms I guess:

对于基于 Solaris 的系统,我发现了这一点.init我猜您可以在每个平台上使用该部分:

   pragma init (function [, function]...)

Source:

来源:

This pragma causes each listed function to be called during initialization (before main) or during shared module loading, by adding a call to the .init section.

通过添加对 .init 部分的调用,此编译指示导致在初始化期间(在 main 之前)或在共享模块加载期间调用每个列出的函数。

回答by Paulo Rossi

It's very simple:

这很简单:

As you should know when you use constants in c, the compiler execute a kind of 'macro' changing the name of the constant for the respective value.

您应该知道,当您在 c 中使用常量时,编译器会执行一种“宏”,为相应的值更改常量的名称。

just include a #defineargument in the beginning of your code with the name of start-up function followed by the name main:

只需#define在代码的开头包含一个参数,其中包含启动函数的名称,后跟名称main

Example:

例子:

#define my_start-up_function (main)