CRT如何调用main,具有不同的参数 [英] How CRT calls main , having different parameter

查看:71
本文介绍了CRT如何调用main,具有不同的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我们可以通过几种方式编写main函数(确保程序中只能有一个main),
1. int main()
2. int main(int argc,char * argv [])
3. int main(int argc,char * argv [],char * environment)

运行时CRT函数如何知道应调用哪个主体.请注意这里,我不是在询问是否支持Unicode.

Hi,

We can write main function in several ways (sure there can be only one main in the program),
1. int main()
2. int main(int argc,char *argv[])
3. int main(int argc,char *argv[],char * environment)

How run-time CRT function knows which main should be called. Please notice here, I am not asking about Unicode supported or not.

推荐答案

我不知道具体的编译器是如何做到的,但是GCC和VC ++附带了源代码.如果需要的话,可以将其代码写入其启动例程.

我前一阵子使用的技巧是使启动代码不必担心main的编写方式.它只是在堆栈上敲了两个字(对于标准编译器而言),并且跳转到调用了称为main的符号.不管程序员已经编写了哪个功能,这两个词都是相同的.不需要太多与编译器的勾结,因为大多数C编译器都依赖于调用函数来清理它们之后的堆栈,而其他语言则依赖于被调用函数的退出代码函数来执行.

干杯,



只为SA:

在大多数编译器上调用main的汇编语言顺序是这样的(假设x86且编译器未在main的末尾添加供应商特定的参数):
I don''t know how specific compilers do it but GCC and VC++ come with the source code to their startup routines if you want a look.

The trick I used a while ago is for the startup code to not worry how main''s been written. It just bungs two words (for a standard compiler) on the stack and jumps to calls the symbol called main. The two words are the same regardless of which of the functions have been written by the programmer. This doesn''t require a lot of collusion with the compiler as most C compilers rely on the calling function to clean up the stack after them while other languages rely on the exit code function of the called function to do.

Cheers,

Ash

Just for SA:

The assembly language sequence for calling main on most compilers is this (assuming x86 and a compiler that doesn''t add vendor specific parameters to the end of main):
push argp
push argc
call main
add  esp, 8


main仅使用ret指令即可返回.

就像我在上面说的那样,在堆栈上放两个单词,调用main(就像我没有编辑我之前从跳转到main时说的那样,ahem),然后依靠调用函数来清理堆栈.

虽然我在谈论这个主题,但是C标准中没有什么可以说编译器无法以相反的方式使用这些单词,而AND/OR依赖main来清理堆栈.因此,没有理由为什么编译器不能使用Pascal或Fortran样式调用约定(MS __stdcall参数没有名称修饰,在某些编译器中为@ 8或@ 12):


main returns just using a ret instruction.

As I said above, bung two words on the stack, call main (like I didn''t edit what I said earlier from jump to main, ahem) and then rely on the calling function to clean up the stack.

While I''m on the subject there''s nothing in the C standard that says a compiler couldn''t either stick the words the other way around, AND/OR rely on main to clean up the stack. So there''s no reason why a compiler couldn''t use a Pascal or Fortran style calling convention (MS __stdcall parameters without the name decoration, the @8 or @12 on some compilers):

push argc
push argp
call main


并依靠main进行ret 8.


and rely on main to do a ret 8.


感谢您根据我的要求澄清问题.

是的,如果您尝试创建一个以上的代码,则开发环境应该会出现诸如不允许main重载"之类的错误.

那么,运行时系统如何知道调用该方法时使用的签名?在一般情况下,不可能进行反射(例如在.NET中),那么如何确定要传递的参数呢?

答案很简单:由于__cdecl有可能在所有情况下都传递最大数量的参数并始终使用返回值.

首先,请注意所有签名都是兼容的:更多高级"签名只会添加其他参数:

Thank you for clarification of the question on my request.

Yes, if you try to create more then one, the development environment should give you an error like "overloading of main is not allowed" or something.

So, how the run-time system knows what signature to use while calling the method? In general case, no reflection is possible (like in .NET), so how to determine what parameters to pass?

Short answer is: it is possible due to __cdecl, by passing maximum number of parameters in all cases and always using return value.

First, pay attention that all signatures are compatible: more "advanced" signature only adds additional parameters:

int main(void)
int main(int argc, char **argv)
int main(int argc, char *argv[]) //same as before
int main(int argc, char **argv, char **envp)



( http://en.wikipedia.org/wiki/Main_function#C_and_C.2B.2B [^ ])

诀窍在这里:参数传递约定.它始终是__cdecl.这是调用方(而不是被调用方)完成堆栈清理时的唯一约定:
http://msdn.microsoft.com/en-us/library/984x0h58%28v = vs.71%29.aspx [ ^ ].

在这种情况下,调用方可以像最长签名一样传递所有参数,并始终返回int值.由于返回值是在CPU寄存器中返回的,因此不会中断对被调用函数的操作,也不会使用它:只需将其忽略即可.所有参数都可以在堆栈上使用,因此被调用函数仅使用其签名所允许的数量.其他所有都将被忽略.由于堆栈是由调用方(运行时系统)清理的,因此它不需要知道被调用方的实际签名是什么 –所有参数都被传递,并且所有参数都被删除.由来电者提供.

尝试明确指定调用约定:



(http://en.wikipedia.org/wiki/Main_function#C_and_C.2B.2B[^])

The trick is here: the argument passing conventions. It is always __cdecl. This is the only convention when the stack cleanup is done by the caller, not the callee:
http://msdn.microsoft.com/en-us/library/984x0h58%28v=vs.71%29.aspx[^].

In this case, the caller can pass all the parameters as in the case of the longest signature and always returns int value. As the return value is returned in the CPU register, it does not disrupt the operation on the called function does not use it: it is simply ignored. All the parameters are available on the stack, so the called function only uses as many as its signature allows; all other are just ignored. As the stack is cleaned up by the caller (run-time system), it does not need to know what was the actual signature of the callee — all parameters are passed, and, respectively, all are removed by the caller.

Try to specify the calling conventions explicitly:

int __cdecl main(int argc, char **argv)


它将编译并链接.尝试使用__stdcall或其他任何方法-链接器将失败.您只能使用__cdecl.之所以如此设计,是出于我上面解释的原因.

—SA


It will compile and link. Try to use __stdcall or any other — the linker will fail. You can only use __cdecl. This is designed so by the reasons I explained above.

—SA


这个问题确实是一个好问题.如果将主函数编译为常规C ++函数,则其名称将被更改,并且运行时系统将无法知道用户提供了哪些各种签名.

这是VC ++的工作方式:查看链接器映射时,您会看到main函数被列为"_main",因此是一个很好的旧C函数,没有名称修饰.这就是运行时找到它的方式.它只是在寻找一个名为"main"的函数.

至于要传递的参数,SA和Ash已经深入解释了该部分.运行时仅将它们压入堆栈或将其传输到寄存器中,然后进行清理.如果main只忽略它们-很好.
The question is indeed a good one. If the main function was compiled as a regular C++ function, its name would be mangled and the runtime system had no way to know, which of the various signatures were provided by the user.

Here is how VC++ does it: When looking at the linker map you see that the main function is listed as "_main", thus as a good old C function, without name mangling. That is how the runtime finds it. It just looks for a function called "main".

As for the parameters that are being passed, SA and Ash have already explained that part in depth. The runtime just pushes them on the stack or transfers them in registers and cleans up afterwards. If main just ignores them - fine.


这篇关于CRT如何调用main,具有不同的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆