为什么在 C++ 中使用 main()不能内联吗?

发布于 2024-11-28 10:47:16 字数 97 浏览 6 评论 0原文

我在阅读 C++ 常见问题解答时注意到一句话。

main() 不能内联。

这是为什么呢?

I was reading the C++ FAQs and I noticed one sentence.

main() cannot be inline.

Why is this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

帅哥哥的热头脑 2024-12-05 10:47:17

有许多基本原因。基本上, main 是从
运行时的基本初始化例程,并且只能从那里开始。
该代码(显然)是在不知道您的 main 的情况下编译的
内联。现代编译器技术能够内联
模块边界,但它是一项高级功能,很多人并不支持
较旧的编译器。当然,内联的好处只是
当函数被频繁调用时出现;根据定义,main
只会被调用一次,不多也不少。

There are a number of basic reasons. Basically, main is called from
the basic initialization routine of the runtime, and only from there.
That code was (obviously) compiled without knowing that your main was
inlined. Modern compiler technology is capable of inlining across
module boundaries, but it's an advanced feature, not supported by many
older compilers. And of course, the benefits of inlining are only
present when a function is called very frequently; by definition, main
will be called exactly once, no more, no less.

天邊彩虹 2024-12-05 10:47:17

我看到标准是这么说的,但真正实际的答案很简单,就是声明添加到每个 C 和 C++ 程序的运行时必须调用可执行文件中的某个点。该函数应该有一个外部符号(以及运行时的地址),以便链接器可以在执行开始时找到要调用的函数。因此,您不能将其声明为内联,因为内联编译器不会为其生成外部符号。

I see the standard says so, but the real practical answer would be as simple as stating that the runtime added to every C and C++ program has to call to some point in the executable. That function should have an external symbol (and address when running) so that the linker can find it to be called at the beginning of execution. Hence you cannot declare it as inline, because inlined the compiler wouldn't generate an external symbol for it.

清风夜微凉 2024-12-05 10:47:17

由于 main() 函数开始执行,因此当代码编译为二进制时,所有内容都在 main() 本身中。所以你可以说,它已经内联了!

是的,在 C++ 程序中使用内联是非法的,这更多的是关于语法!

Since its the main() function, which starts the execution, when the code gets compiled to binary, everything is in the main() itself. so you can say, it already inlined!

And yes, its illegal to use inline for your C++ program, that's more about a syntax!

倒数 2024-12-05 10:47:17

对于大多数编译器/架构的组合,源代码中的 main() 函数在最终的二进制文件中成为相当正常的函数。这只是因为它在这些架构上很方便,而不是因为标准规定必须如此。

在内存受限的架构上,许多编译器(生成平面二进制文件(如 intex 十六进制格式)而不是动态链接器友好容器(如 elf 或 xcoff))会优化所有样板文件,因为它只会变得臃肿。有些架构根本不支持函数调用(在这些平台上只能使用 C++ 的有限子集。)

为了支持最广泛的此类架构和构建环境,标准选择保留 main( ) 尽可能开放,以便编译器可以为最广泛的平台做正确的事情。这意味着该语言中提供的许多功能作为一个整体不能应用于应用程序本身的启动和关闭。

如果您需要类似内联 main() (或可重入,或任何奇特的功能)之类的东西,您当然可以将 main 函数称为其他名称:

inline int myMain(int argc, char **argv) { /* whatever */ }
int main(int argc, char **argv) { return myMain(argc, argv); }

For most combinations of compiler/archetecture, the main() function in the source becomes a reasonably normal function in the final binary. This is only because it's convenient on those archetectures, not because the standard says it must be so.

On memory constrained archetectures, many compilers, ones which produce a flat binary (like intex hex format) instead of a dynamic linker friendly container (like elf or xcoff), optimize all of the boilerplate away, since it would just be bloat. Some architectures don't support function calls at all (only a limited subset of C++ is possible on these platforms.)

In order to support the widest variety of such architectures and build environments, the standard elects keep the semantics of main() as open as possible, so that the compiler can do what's right for the widest variety of platforms. That means that many features available in the language as a whole cannot apply to the startup and shutdown of the application itself.

If you need something like an inline main() (or reentrancy, or any fancy feature) you can of course call the main function something else:

inline int myMain(int argc, char **argv) { /* whatever */ }
int main(int argc, char **argv) { return myMain(argc, argv); }
茶色山野 2024-12-05 10:47:17

内联函数默认具有静态作用域。这意味着如果我们将 main() 声明为内联,它的范围将仅限于定义它的文件。然而,C 启动库(由编译器供应商提供)需要“main”作为全局符号。有一些编译器允许使用链接器标志修改入口点函数(例如 main)。

Inline functions are having static scope by-default. It means if we declare main() as inline, it's scope will be limited to the file where it is defined. Yet, the C start-up library (provided by compiler vendor) needs 'main' to be a global symbol. There are some compilers that allow to modify entry point function (e.g. main) using linker flags.

氛圍 2024-12-05 10:47:17

内联函数通常没有地址,因此没有可移植的方式来调用 main,main() 需要一个 init 代码可以跳转到的地址。内联函数意味着嵌入到调用函数中,如果 main 是内联的,则应该内联到程序的 init 代码中,这也是不可移植的。

inline functions don't usually have an address, so there is no portable way to call main, main() needs an address on which the init code can jump into. Inlined functions are meant to be stuck into the calling function, if main is inlined, it should be inlined into the init code of the program, which is not portable either.

怎言笑 2024-12-05 10:47:17

操作系统将二进制数据加载到内存;寻找入口点(c/c++ 中的“主”符号);远跳转到入口点标签的地址。在程序未加载之前,操作系统对代码中的主函数一无所知。

operating system loads binary data to memory; looks for entry point (the 'main' symbol in c/c++); makes far jump to the addres of the entry point label. Operating system does not know anything about main function in your code until the program is not loaded.

岁月染过的梦 2024-12-05 10:47:16

在 C++ 中,在代码中调用 main 函数是不合法的,因此不可能内联它。

In C++ it is not legal to call the main function in your code, so there'd be no way it could ever be inlined.

本宫微胖 2024-12-05 10:47:16

因为标准是这样说的:

<代码>[2003:3.6.1/3]:
不得在程序中使用 main 函数 (3.2)。这
main 的链接 (3.5) 是实现定义的。 一个程序
声明 main 为内联或 static 的格式不正确。
名称 main 是
不另行保留。 [示例:成员函数、类和
枚举可以称为 main,其他命名空间中的实体也可以。
]

为什么这么说呢?因为它试图将 main 的实现尽可能多地留给个人......好吧,实现 ..尽可能,并且不希望通过要求来限制实现当内联可能没有实际好处时,它在这里是有效的。


我在委员会的朋友证实了这一点:

inline main() 本身没有理由不起作用。 [..] 我可以有一个可以调用内联 main() 的 C++ 解释器。 [..] [但是] 禁止 inline/static main() 以避免混淆。我发现很难想象其基本原理除了[本问答]中已经说过的内容之外还有什么其他内容。


顺便说一句,不要将 inline 提示关键字与实际的内联函数混淆。您可以将函数标记为内联,但它可能不是物理内联的。

因此,即使 main 确实“无法内联”(严格来说,这是,尽管内联 main 会更合适)正如其他答案中所解释的那样,尴尬且毫无意义),理论上它仍然可以很好地支持 inline 提示关键字。

事实并非如此,正如 litb 的回答所述:这会使事情变得复杂,而没有真正的好处。

Because the standard says so:

[2003: 3.6.1/3]:
The function main shall not be used (3.2) within a program. The
linkage (3.5) of main is implementation-defined. A program that
declares main to be inline or static is ill-formed.
The name main is
not otherwise reserved. [Example: member functions, classes, and
enumerations can be called main, as can entities in other namespaces.
]

And why does it say so? Because it's trying to leave as much about the implementation of main to the individual .. well, implementation .. as is possible, and doesn't want to limit implementations by requiring that inline be valid here when it arguably has no practical benefit.


My friend on the committee confirmed this:

There's no reason why an inline main() wouldn't work, per se. [..] I could have a C++ interpreter that can invoke inlined main(). [..] [But] inline/static main() are forbidden in order to hopefully avoid confusion. I find it hard to imagine that the rationale would be anything additional to what's already been said in [this Q&A].


BTW, don't confuse the inline hint keyword with actually inlining functions. You can mark a function inline and it may not be physically inlined.

So, even if it were true that main "cannot be inlined" (and strictly speaking it is not true, though inlining main would be rather awkward and pointless as explained in other answers), it could theoretically still support the inline hint keyword just fine.

It doesn't for the reason stated above, and in litb's answer: it would complicate matters for no real benefit.

叹倦 2024-12-05 10:47:16

C 运行时库需要找到此符号才能“知道”要运行哪个函数。

The C runtime library needs to find this symbol in order to "know" which function to run.

无戏配角 2024-12-05 10:47:16

你不能直接调用 main() (在 C++ 中是禁止的),所以没有必要内联它。

You cannot directly call main() (it's forbidden in c++), so there is no point of inlining it.

夕嗳→ 2024-12-05 10:47:16

通常 main() 是从系统 init() 函数中调用的。因此,main() 需要只有一个定义

现在,如果我们可以内联 main() 函数并将其包含在头文件中,那么对于每个翻译单元,main()< 都会有不同的定义/代码>。这是不允许的。您可以在命名空间中声明main()内联它。但不是全局 main()

Usually main() is called from systems init() function. Thus, it is needed that there can be exactly one definition for main().

Now, if we can inline the main() function and include in a header file then, for every translation unit there will be different definition for main(). Which is not allowed. You can declare main() in a namespace and inline it. But not the global main().

薔薇婲 2024-12-05 10:47:16

首先,您必须了解内联示例的工作原理

 inline void f() {
     int a  = 3;
     a += 3;
     cout << a;
 }

 int main() {
      f();
      return 0;
 }

对于编译器来说,它看起来像:

 int main() {
        int a  = 3;
        a += 3;
        cout << a;
        return 0;
 }

看这个示例,您希望如何使 main 内联?该方法立即内联。

firstly you must understand how work function with inline

example:

 inline void f() {
     int a  = 3;
     a += 3;
     cout << a;
 }

 int main() {
      f();
      return 0;
 }

will look like to the compiler as:

 int main() {
        int a  = 3;
        a += 3;
        cout << a;
        return 0;
 }

looking at this example, how do you want to make main inline? This method is inline immediately.

绻影浮沉 2024-12-05 10:47:16

根据 @Tomalak Geret'kal 的回复,C++ 标准规定 main 函数不能内联。此响应讨论了如果标准中的限制被删除,内联 main 函数的可能性。

内联的定义
inline 关键字是对编译器在原位粘贴函数内容的建议。一个目的是消除调用函数(子例程)和返回函数时存在的开销。

内联的一个重要情况是存在指向函数的指针的情况。在这种情况下,必须至少有一个该函数的静态副本。在这种情况下,链接器可以解析内联函数的“外部链接”,因为存在一个静态版本。

需要注意的是,编译器和链接器确定是否粘贴内容或调用函数的单个实例。

另外值得注意的是,未由程序员标记的函数也可能由编译器内联。

内联main函数
由于只允许调用一次 main,因此它的如何链接取决于编译器。标准允许内联函数的单个实例。编译器可以将内联函数转换为对单个实例的函数调用。因此编译器会忽略main函数的内联建议。

编译器和链接器必须确保内联 main 函数仅存在一个实例。这就是棘手的部分,尤其是外部链接。确保一个实例的一种过程是留下翻译具有“主要”功能的信息,无论它是否内联。 注意:当调用内联函数时,编译器可以从符号表中删除该函数以进行外部链接,因为这个想法是该函数不会被外部函数调用。 >

总结
技术上,没有什么可以阻止 main 函数被内联。用于将内联函数转换为单个实例以及识别函数的多个实例的机器已经存在。当存在指向内联函数的指针时,就会创建函数的单个实例,因此它有一个地址。该机器将满足运行时库对具有地址的 main 的要求。对于 main 函数的 inline ,它将被忽略,但不应该有任何理由阻止这种语法(除了令人困惑的人)。毕竟,已经存在冗余的语法情况,例如将按值(副本)传递的参数声明为 const。

“这只是我的意见,我可能是错的。” ——丹尼斯·米勒,喜剧演员。

The C++ standard says that the main function cannot be inlined, per @Tomalak Geret'kal's reply. This response discusses possibility of inlining of the main function, were the restriction in the Standard removed.

Definition of Inline
The inline keyword is a suggestion to the compiler to paste the contents of the function in-situ. One intent is to remove the overhead present in calling and returning from a function (subroutine).

An important situation of inlining is the case where there is a pointer to the function. In this case, there must be at least one static copy of the function. In this case, the linker can resolve "external linkages" of the inlined function because there is one static version.

Important to note that the compiler and linker determine whether or not to paste the contents or calls a single instance of the function.

Also of note, functions that are not tagged by the programmer may also be inlined by the compiler.

Inlining the main function
Since there is only one invocation of main allowed, how it is linked is up to the compiler. Single instances of inline functions are allowed by the Standard. The compiler is allowed to convert an inlined function into a function call to a single instance. So the compiler would ignore an inline suggestion for the main function.

The compiler and linker would have to insure that only one instance of the inlined main function exists. This where the tricky part comes in, especially with external linkage. One process for ensuring one instance is to leave information that a translation has a 'main' function whether or not it is inlined. Note: When a call to an inline function is made, the compiler is allowed to remove the function from the symbol tables for external linkage, since the idea is that the function won't be called by external functions.

Summary
Technically, there is nothing preventing the main function from being inlined. The machinery already exists for converting inlined functions into single instances and for identifying multiple instances of a function. When there is a pointer to an inlined function, a single instance of a function is made, so it has an address. This machinery would satisfy the Run-Time Library requirements for main having an address. In the case of inline for the main function, it would be ignored but there should not be any reason to prevent this syntax (except confusing people). After all, there are already syntax cases that are redundant, such as declaring a parameter that is passed by value (copy) as const.

"That's just my opinion, I could be wrong." -- Dennis Miller, comedian.

迷路的信 2024-12-05 10:47:16

其他人评论说,在机器代码级别内联 main 的调用没有意义。那是垃圾。它需要链接器的一些帮助(例如全局优化),或者每个应用程序重新编译一些运行时库,但这是完全可行的,这里没有技术问题。

但是,内联暗示效果(即调用最好是内联的)与仅调用一次且处于控制顶层的函数无关,如>主要是。

内联的唯一保证效果是允许在两个或多个翻译单元中(相同地)定义外部链接函数,即影响单一定义规则。

实际上,这允许将定义放置在头文件中,并且将其放置在头文件中实际上也是保证相同定义所必需的。

这对于 main 来说没有意义,因此 main 没有理由内联

Others have remarked that an invocation of main can not meaningfully be inlined at the machine code level. That's rubbish. It would require a bit of help from the linker (like global optimization) or else per-application recompilation of a bit of the runtime library, but it's quite doable, no technical problem here.

However, the hinting effect of inline, that calls should preferably be inlined, is irrelevant for a function that is only called once and at the top level of control, as main is.

The only guaranteed effect of inline is to allow an external linkage function to be defined (identically) in two or more translation units, i.e. affecting the One Definition Rule.

As a practical matter this allows the definition to be placed in a header file, and placing it in a header file is a also practically necessary to guarantee identical definitions.

That does not make sense for main, so there is no reason for main to be inline.

烦人精 2024-12-05 10:47:16

您只能定义一次main。因此,放置 inline 不会有任何目的 - inline 仅对可以在程序中定义多次的函数有重要作用(所有定义都将被视为只有一个定义且所有定义必须相同)。

因为 inline 函数可以在程序中定义多次,并且 inline 还可以快速调用 inline 标记的函数该标准尽可能要求在使用该标准的每个翻译单元中定义内联函数。因此,如果函数的定义是内联的,并且当前翻译单元中的代码未使用该函数,那么编译器通常会丢弃该函数的定义。对 main 这样做是完全错误的,这表明 inlinemain 的语义完全不兼容。

请注意标题中的问题“为什么 C++ 中的 main() 不能内联?”您从标准中引用的声明涉及不同的事情。您问的是函数是否可以内联,通常理解为将被调用函数的代码完全或部分插入到调用函数中。仅将函数标记为内联并不意味着内联该函数。这完全是编译器的决定,当然,如果您从不调用 main(并且您不能这样做),那么就没有什么可以内联的。

You can only define main once. So putting inline would not serve any purpose - inline only has a significant purpose on functions you can define multiple times in a program (all definitions will be treated as if there were only one definition and all definitions are required to be the same).

Because inline functions can be defined multiple times in a program, and inline also serves the purpose of making calls to an inline-marked function as fast as possible, the Standard requires inline functions to be defined in every translation unit in which it is used. So compilers will usually throw away the definition of a function if it is inline and the function wasn't used by the code in the current translation unit. To do that for main would be entirely wrong, which goes to show that inline and the semantics main has is entirely incompatible.

Note that the question in your title "Why main() in C++ cannot be inlined?" and the statement you quote out of the Standard concern different things. You are asking whether the function can be inlined, which commonly is understood to insert the code of a called function completely or partially into the calling function. Just marking a function inline doesn't imply inlining that function at all. It's entirely the compiler's decision, and of course if you never call main (and you cannot do so) then there is nothing to be inlined.

少钕鈤記 2024-12-05 10:47:16

如果您静态链接到 CRT并且启用了一些链接时编译内联(如 MSVC 那样),则可能可以内联它。

但这确实没有意义。它将被调用一次,并且与 main 中第一行执行之前完成的所有其他操作相比,该函数调用开销几乎为零。

...

Aaand,这是强制符号在可执行文件中仅出现一次的简单方法。 :)

If you linked statically to the CRT and enabled some link-time compilation-inlining (like MSVC has) it might be possible to inline it.

But it doesn't really make sense. It will be called once and that function call-overhead is practically naught compared to everything else that is done before the first line in main executes.

...

Aaand, it is an easy way to force the symbol to appear only once in your executable. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文