【C/C++_非_值班室】归来哟,故乡的云:Inline再讨论 (翻译)星星兄们,进来帮个忙。外加放分引人看~

dot99 2004-07-13 09:03:22
下面的文章翻译自GotW.
由于最近工作+学校的原因,暂时不会上网了,要等把所有事情都搞定了再说~
后面两段没翻译完,留在硬盘里面又觉得心里面痒,大家帮忙翻译一个~

用句常用的话拜托一下:“冰天雪地裸女960度回旋飞跪,泪如雨下,声嘶力竭,xxxx, ...., ****, @@@@, 拜托了~~~~”(这女的好累...)

====================

归来哟,故乡的云:Inline再讨论

作者: Herb Sutter
翻译: hardcoreX.雪糕.dot99.计算机她姑爹 (其实都是我)

快!选择一个。

什么时候内联表现出来?

A.写代码的时候
B.编译的时候
C.连接的时候
D.程序装入的时候
E.运行期
F.其他某个时候

另外:什么函数能够保证永远不会被内联?

打住!想想,然后再往下看。

你选啥呢?如果你选了A或者B,呵呵,你有伴了。这两个是常见的答案,去看看[1]的第十二款,我对C++中inline关键字的详细讨论。如果那解释就够了的话,我们就停在这里了,放编辑们一个假,然后再把剩下的栏目做了。但是现在不能,因为还有好多要讨论,很多很多。

我写这篇文章是想说明:第一个问题的最准确的答案是“全部正确或者没有一个正确。”第二个问题的答案是“没有。”为什么呢?继续往下看。

如果一已经阅读了[1]的第十二款,下面的部分就是一个复习,如果你没有思考过C答案的话,你也可以轻轻掠过。

简单的说,“内联行为(inlining)”就是将函数在调用的地方原地展开函数体。看看下面的代码:

// Example 1
//
double Square( double x ) { return x * x; }

int main() {
double d = Square(3.14159 * 2.71828 );
}

内联后,这个函数调用就好像以如下代码替代了(概念上):

int main() {
const double __temp = 3.14159 * 2.71828;
double d = __temp * __temp;
}

这个内联动作消除了调用函数的开销,即是参数压栈和代码转移的开销,因而也省去了临时引用(losing some locality of reference)。这个内联行为不等同于宏,因为一个内联函数调用一样的是一个函数调用,它的参数只被评估[译注:平时都叫“计算”,但是我觉得这里用“评估”比较好]一次。但是,一个宏则要将它评估多次,即宏#define SquareMacro(x) ((x)*(x))在调用的时候,如SquareMacro(3.14159*2.71828),要被展开为3.14159 * 2.71828 * 3.14159 * 2.71828(计算PI*e两次,而不是一次)。

顺便提一下,你注意到例1出现内联行为(inlining)没有?我们没有使用关键字inline。这是故意的。等下我们还要来讨论这个有趣的问题。

答案A:写代码的时候
当开发者们写程序的时候,念出inline的咒语。那不是真正的就内联(没有发生内联行为),只是一个想要内联试图而已,所以,我们可以将A看做是最早的决定内联动做(inlining)的一个机会。

当你试图在你的代码里面写上inline关键字的时候,你必须要记得三件重要的事情。

首先,不要那么做。过早的优化会带来麻烦,你不应该在没有证明需要加入inline才能提高效率的情况下试图加入这个关键字。翻翻[1]的第十二款和[3],里面夸张地指责和严重警告这种程序过早优化和过早决定内联的行为。

它(inline)仅仅是“请,一定要”的意思。这个在[1]的第十二款说过,inline关键字只不过是对编译器的暗示,让你巴结(sweet talk)编译器,让他给你这样做。(关于”巴结”的卑劣行径,下面讨论。)这就是全部:inline关键字并没被要求在C++程序中拥有任何语义上的效果。它并没有影响到标准语言的其他部分,用了inline关键字并没有要你改变函数的用法(例如,你仍然可以获得这个函数的地址),也不可能要标准C++编译器去检测一个函数究竟被声明为内联没有。

行为(inlining)真正表现出来,是在调用的时候。这个差别非常重要,因为这个函数能(应该经常能)在被调用的地方被内联而不是其它的地方;写下inline没有给你任何方式去表达这个事实。因为我们能做的只有在函数前面写inline关键字,我们这样做了,是给编译器含蓄的说,这个函数适合在调用的地方内联。这个预见[译注:内联一个函数]很少准确。我们经常说“内联这个函数”, 准确的说,你最好增加一下你的词汇量,应该是“内联这个函数的调用”("inlining a function call")

答案B:编译的时候
在编译的时候,编译器会像例1那样例行公事。

编译器会做什么?当我们勾对她(sweet-talk it, 哈哈哈),给她说,这个函数要内联的时候。这个要看是谁了。并不是所有女人[译注:原文是编译器]对甜言蜜语有反应,甚至在巧克力和鲜花的轰炸下。有时,你的编译器(或者其他工具)会不甩你而我行我素:

l 拒绝内联你要求内联的函数调用。
l 内联你并没有声明的函数的调用。
l 内联一些函数调用而不管声明要内联没有,或者一些地方内联,另外一些地方则不。

再注意例1,我们并没有在任何地方写下“inline”。这是故意的,我是想说明,那个样子一样会发生内联行为。确实是,不需要对你现在使用的编译器所做的一切大惊小怪。因为,你也不能再写出一个其他的程序来找茬,这是一个合理的优化,编译器能(而且经常能)为了你的利益着想。

现在的编译器能比程序员在决定那个函数调用需要内联上要出色,包括是否要展开同一个函数在某个调用的地方,而不在另外的地方。为什么?最简单的答案是,编译器比你知道得要多,它知道调用的“真实”的结构——函数调用被优化后的机器码,包括解开循环和去除无效分枝(“if-else”, “switch-case”),所有的这些工作,编译器都做了。例如,编译器也许会检测到这个被内联的函数如果放进一个循环里面,会使这个循环过大,而代码cache不能容纳,导致整体性能下降。编译器会选择在这个循环里面不内联这个函数调用,而也许会在其他地方内联它。


...全文
297 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
languagec 2004-07-17
  • 打赏
  • 举报
回复
sanyou98 2004-07-17
  • 打赏
  • 举报
回复
up
SBNOone 2004-07-17
  • 打赏
  • 举报
回复
mark
dot99 2004-07-17
  • 打赏
  • 举报
回复
兄弟伙帮忙翻译一下嘛~~
要不等我明天飞回来再说.....--;;
peter9606 2004-07-14
  • 打赏
  • 举报
回复
up
riitso 2004-07-14
  • 打赏
  • 举报
回复
好长
wasoxi 2004-07-14
  • 打赏
  • 举报
回复
UP
expert2000 2004-07-14
  • 打赏
  • 举报
回复
家庭办公一直是我的梦想,可惜现在还没有这个实力。只好躲到csdn上苦练。天天把这6页帖子灌一遍水,希望能早日家庭办公。^!^
eboywy 2004-07-14
  • 打赏
  • 举报
回复
坐下来慢慢看。
langzi8818 2004-07-14
  • 打赏
  • 举报
回复
顶下先
autoegg 2004-07-14
  • 打赏
  • 举报
回复
搬个凳子先,:)
xjp6688 2004-07-14
  • 打赏
  • 举报
回复
好贴!!!
dot99 2004-07-13
  • 打赏
  • 举报
回复
。。。。。一个人哦。。。。
名字换了换而已。。。
bm1408 2004-07-13
  • 打赏
  • 举报
回复
study and save!
happyasen 2004-07-13
  • 打赏
  • 举报
回复
UP
hcj2002 2004-07-13
  • 打赏
  • 举报
回复
楼主好多马甲呀!
BluntBlade 2004-07-13
  • 打赏
  • 举报
回复
我E文学差了……帮顶。
dot99 2004-07-13
  • 打赏
  • 举报
回复
还好你占个位置,要不然我说不了话了~~~

我现在是 学校不放人,老板不放人, 最后看我~我当然是要留学校啊~
结果老板让我做家庭办公(不敢用英文^_^),还说公司电脑留给我~我怎么办哦~~~~以后跑不出这个老板的手心了。。。。。。明天开始办最难办的事情了~~上不了网了,大家帮忙帮忙翻译完这篇~
leonchew 2004-07-13
  • 打赏
  • 举报
回复
呵呵,dot99 ,还不少了!
占个一楼先,等星星们来!
dot99 2004-07-13
  • 打赏
  • 举报
回复
答案D:程序装入的时候
高高兴兴地把我们的软件编译,连接,压进安装包里面,自豪地刻在CD上卖给我们的第一个用户。现在该高兴地a)收钱;b)开个party;和c)大声的说,内联(inlining)不就是那么点点东西!对不对?

答案是:对,对,绝对不对。

自从1990年中期以后,面向集成运行环境的软件数量逐增长。就是说把程序编译为机器码以适应某种芯片或者用API函数为某种系统写作程序,替换为把程序编译为字节码(bytecode stream),然后通过用户机器上的运行环境,通常不依赖某种CPU或者操作系统,再翻译或者编译为可执行代码。常见的,但不只有这些,如JAVA虚拟机(JVM)还有.NET通用语言运行库(CLR)(包括它的兄弟姐妹,如Mono和Rotor,都是基于ISO Common Language Infrastructure(CLI)标准(一个CLR的子集)来实现。当面向这些运行环境编程时,编译器把原始C++代码翻译成字节码,将一个程序重写为运行环境所接受的指令码(opcode)。

另外:一些这样的运行环境带有一个丰富的指令集,这些指令集包含着高度的面向对象理论,包括类、继承和虚函数,作为直接的坚强后盾。一个面向此平台的编译器能(而且经常这样)把源程序,按照严格的类到类,函数到函数(class-for-class, function-for-function)基本规则,翻译成目标指令语言,这可能是在在编译期优化之后做的,比如一些函数调用得内联化。如果编译器这样做了,那么源程序中C++函数就会或多或少直接被运行环境中拥有相同函数签名(signature)的指令集再现出来。
当然,一个编译器不会将所有的事情搞得完全一样, 也没有必要完全一样.内联行为在加载程序的时候是怎么表现的呢?在托管环境下,最终CPU也不得不将这些指令反馈为本地机器码集。因此,托管环境只是负责把语言指令翻译为CPU能执行的机器指令。这一步通常在程序第一次装载的时候进行,并且在这个时候,正像其他许多compilation-like(不会翻译)进程,更进一步的优化也能(并且经常)被进行。特别地,.NET CLR在程序装载时进行了一些内联的行为。

这写托管环境下的行为并不是由语言特性所决定的,所以,这些在程序装入时进行的优化(包括内联)能被跨语言的执行。不要惊讶你的C#程序内联了一个C++的函数。

现在内联是不是太晚了一点?不要说不可能啊,因为inline的故事还没结束…

答案E: 运行时
够了够了,现在我们到了程序运行时候,我们应该告别代码级别的优化了,对吗?
看上去好像不能在程序运行时进行内联优化,但是实际上有很多方法能够做到。
It might seem impossible that inlining can still be performed at runtime, but in fact there are several ways it can be done. In particular, I want to mention profile-directed optimization and guarded inlining. Like a managed environment (see previous and next sections), this requires some tool support to exist on the user's machine at runtime.

The idea behind profile-directed optimization is that when the application is actually run, instrumentation hooks inserted into the executing program can gather data about how the program is actually being used, in particular what functions are being called heavily and under what conditions (e.g., the size of the working set compared to the total cache memory when the function is called). The data gathered from these instrumented hooks can be used to modify the executable image so that selected function calls can be inlined to tune the application to its target environment based on actual runtime performance measurements.

Guarded inlining is another example of how aggressive the runtime inline optimizations can be. In particular, [4] and [5] document the Jikes Research Virtual Machine (RVM), née the Jalapeño dynamic optimizing compiler, for JVM targets. Among other things, this compiler is able to inline virtual member functions by assuming that the receiver of the virtual call will be of a given declared type (in order to avoid the cost not only of the function call but of the extra expense of virtual dispatch). Now, compilers can already routinely nonvirtualize (and therefore also optionally inline) certain virtual function calls today, if the type of the target is statically known. What's new here is that the Jikes/Jalapeño environment can nonvirtualize and inline calls to virtual functions even if the static type of the target is not known. Because the guess might not be right, it inserts a guard that performs a runtime check that validates that the target object's type is what was expected; if it's not, it falls back to a normal virtual function call.

答案F: 其他某个时候
Finally, I'll add one "other time" example I can think of, which is similar to some of the others but distinct enough that I'll give it its own section.

Recall that in Answer D we considered inlining that happens when installing applications on certain managed runtime environments, such as a JVM or .NET CLR environment. Of course, Astute Readers will already have noticed that earlier I only mentioned translation from bytecode to native machine instructions at application installation time, but there's another and more common time when that translation takes place, namely at JIT time, where JIT refers to "just-in-time" compilation.

The idea behind JITting is to compile functions "just in time," just before they're about to be used. This has the advantage of amortizing the cost of compiling the program down to native code, because of instead of one big compilation step you get lots of little compilations for individual parts of the code, just as they're about to be used. It has the corresponding disadvantages of potentially making the first runs of a program somewhat slower, and of reducing the quality of optimization because the JIT has to be fast and can't afford to spend a lot of time analyzing inlining and other optimization opportunities. A JITter can still perform optimizations like inlining, but we can generally get better results by doing the same work earlier, say at application installation time (see Answer D above) when we're not so time-sensitive and the compiler can spend the cycles to do more analysis.

Summary
Like all optimizations, inlining is frequently better when performed by tools that are aware of the generated code and/or the execution environment rather than by the programmer. The later it is performed, the more specific and targeted it can be.

We talk about inlining functions, but it's more correct to say that we perform inlining on function calls. After all, the same function may be inlined in one place but not in others. And, because of the many opportunities that exist for inlining even well after initial compilation has finished, the same function can be inlined, not only in different places, but by different tools in each place.

There's more to inlining than the inline keyword alone.

References
[1] H. Sutter. More Exceptional C++ (Addison-Wesley, 2002).
[2] Arguably, another interpretation of "at coding time" is that some developers literally inline at coding time by physically moving blocks of source code around. That's not the usual meaning of "inlining" and so I'll ignore it.
[3] http://www.google.com/search?q=site:www%2Egotw%2Eca+premature (various references to premature optimization in articles that I've written).
[4] M. Arnold et al. "Adaptive Optimization in the Jalapeño JVM" (Proceedings of the conference on Object-oriented programming, systems, languages, and applications, ACM Press, 2000).
[5] Jikes RVM home page.
加载更多回复(1)
“1-考试报名系统1”项目是一个数据结构课程设计,旨在创建一个考试报名系统。该项目由汪明杰同学在软件学院软件工程专业,同济大学进行,指导教师为张颖。 本文档详细阐述了项目的分析、设计、实现和测试过程。首先,项目背景指出考试报名系统对学校教务管理的重要性,特别是在处理大量考试人员时的挑战。接着,项目需求分析部分明确了系统应具备的功能,包括用户友好性、数据处理能力等。 在项目要求中,功能要求详细列出了系统应具备的各个功能,如: 1.3.1 功能要求:这可能包括考生注册、考试选择、报名、取消报名、查询考试信息等功能。 1.3.2 输入格式:可能涉及考生信息输入的格式规范,如姓名、学号、选择的考试科目等。 1.3.3 输出格式:可能涉及打印报名成功通知、查询结果展示等输出信息的格式。 项目设计部分讨论了数据结构和类的设计: 2.1 数据结构设计:可能使用数据结构如链表来存储和管理考生信息和考试数据。 2.2 类设计:包括结点类(ListNode)、双向链表类(List)以及数据库类(DataBase),用于构建系统的核心结构。 在项目实现章节,详细描述了各个功能的实现逻辑和代码,包括: 3.1 项目主体功能:涵盖系统的整体流程和代码实现。 3.2 项目初始化:如何加载初始数据,包括读取文件和手动输入。 3.3 插入数据:添加新的考生信息或考试报名。 3.4 删除数据:取消考生的报名。 3.5 修改数据:更新考生信息或考试选择。 3.6 查询数据:根据特定条件查找考生信息或考试详情。 3.7 统计数据:可能包括统计报名人数、考试科目选择情况等。 最后,项目测试部分涵盖了各种测试用例,确保系统的正确性和稳定性,如: 4.1 项目初始化测试:验证数据加载功能。 4.2 插入、删除、查找、修改和统计测试:分别检查各功能是否正常工作。 4.7 边界测试:测试特殊情况,如插入已存在的考生、删除不存在的考生等。 这个“1-考试报名系统1”项目涵盖了软件开发的完整生命周期,从需求分析到设计、实现和测试,体现了软件工程中的核心原则,特别是数据结构的应用和系统功能的实现。
根据提供的文件信息,本知识点将围绕“postprocess_swan”笔记本集合及其相关的SWAN数值模型后处理过程展开。 标题中的“postprocess_swan”指出这是一个专门用于后处理SWAN(Simulating Waves Nearshore)数值模型结果的笔记本集合。SWAN模型是一个广泛应用于近岸海域的波浪模拟工具,它可以模拟和分析波浪传播、生成、折射、反射、叠加以及破碎等现象。SWAN模型结果的后处理是整个模拟过程中的重要环节,它能够帮助研究人员分析波浪的特征,预测波浪对海岸线和海洋工程结构的影响。后处理包括数据可视化、数据统计、结果验证和解释等多个方面。 描述中提到的“后处理天鹅”,可能是对“postprocess_swan”的一种形象描述,但应该是指对SWAN模型输出结果的处理过程,而不是指某种生物或实体。 由于文件信息中未提供具体的标签内容,我们无法从这个角度提供相关的知识点。然而,“postprocess_swan-master”文件名暗示了这可能是一个开源项目,通常以“-master”结尾的文件名称表示这是一个包含源代码、数据文件、说明文档等资源的仓库主分支。 现在,让我们探讨几个与“postprocess_swan”相关的具体知识点: 1. SWAN模型简介: - SWAN全称为“Simulating Waves Nearshore”,是一种用于计算近岸波浪的数值模型。 - 它基于波浪运动的物理原理,包括波浪能量平衡方程。 - SWAN模型可以模拟波浪的成长、衰减、折射、绕射、反射和底摩擦等物理过程。 - 该模型适用于海浪、风浪、以及与海浪相关的波浪动力学问题的研究。 2. SWAN模型的应用: - 风暴潮和极端天气事件下波浪高度和周期的模拟。 - 海岸线工程的波浪载荷分析,如防波堤、海堤和人工岛的波浪作用评估。 - 环境影响评估,比如石油平台、海上风电场以及港口的建设和运营对波浪场的影响。 - 海洋资源开发,例如海底油气管道铺设和维护过程中的波浪条件预测。 3. SWAN模型后处理的重要性: - 通过后处理可以验证SWAN模型的准确性,确保模拟结果的可靠性。 - 后处理过程包括数据的提取、整理和分析,有助于更好地理解模型输出。 - 数据可视化是后处理中不可或缺的一部分,可以直观地展现波浪场的分布特征。 - 结果解释和验证通常需要与现场观测数据或其他模型预测结果对比。 4. 后处理过程中的常见操作: - 绘制波浪玫瑰图、等值线图和波高分布图等。 - 计算波浪的方向谱、频率谱和波浪能量分布。 - 使用统计分析工具,如计算波浪的平均周期、有效波高和波浪方向。 - 提取特定区域或时间点的波浪数据,进行局部细节分析。 5. SWAN模型后处理工具和方法: - 后处理工具可能包括SWAN自带的分析模块、Matlab、Python或R语言中的数据处理脚本。 - 对于可视化,可能会使用专业的数据可视化软件,如Surfer、QGIS、ArcGIS或者其他开源工具。 - 模型结果通常需要与测量数据(如ADCP数据、水位计数据)或其他模拟结果进行对比验证。 6. 开源项目“postprocess_swan”的特点和功能: - 可能提供了一套完整的后处理流程模板,便于研究人员直接使用。 - 包含了多种数据分析和可视化的方法,提高了工作效率。 - 作为一个开源项目,它可能具备良好的社区支持,方便用户提出问题和改进意见。 - 随着项目的发展,还可能包含用于处理SWAN模型不同版本输出结果的适应性调整功能。 通过以上知识点的阐述,我们可以看到“postprocess_swan”笔记本集合对于SWAN模型结果后处理的重要性和实用性。对于海洋工程、海岸工程以及海洋环境研究领域的科研人员来说,一个功能完善的后处理工具是他们进行数据分析和科学发现的关键支持。
【正文】 电脑主板型号修改软件v1.1是一款专门针对计算机主板信息进行调整的工具,主要功能在于修改主板的品牌、型号、序列号以及BIOS版本等信息。在IT行业中,这种软件的应用通常与硬件测试、系统优化或者修复某些特定问题有关。然而,需要注意的是,法篡改这些信息可能涉及法律问题,因此在使用时应遵循合法合规的原则。 主板是计算机的核心部件,负责连接各个硬件组件并提供数据交换的平台。主板的品牌和型号决定了其兼容性和性能,而序列号则是主板的身份标识,用于区分每块主板的独特性。BIOS(基本输入输出系统)则是主板上的一段固件,负责引导操作系统启动和管理硬件资源。 该软件允许用户自定义这些信息,有以下几个可能的用途: 1. **硬件测试**:在开发或测试新硬件时,制造商可能需要模拟不同类型的主板环境。通过修改主板信息,可以快速创建多种测试场景,以确保新硬件在各种配置下都能正常工作。 2. **系统优化**:某些应用程序或游戏可能会对特定主板型号有优化,修改主板信息可能有助于提升性能或解决兼容性问题。不过,这并不总是有效,也可能导致其他问题。 3. **故障排除**:在某些情况下,错误的主板信息可能导致驱动程序安装失败或系统运行异常。修改这些信息有时可以帮助诊断和解决问题。 4. **安全风险**:值得注意的是,法修改主板信息也可能被用于欺骗目的,如逃避保修期限制或进行法活动。因此,使用此类软件需谨慎,并且要清楚可能带来的法律风险。 在使用"电脑主板型号修改软件v1.1.exe"前,用户应确保具备一定的电脑硬件知识,理解操作可能带来的后果。同时,备份重要的数据是必要的,因为不正确的修改可能会导致系统不稳定甚至无法启动。在执行修改前,了解主板的原始信息,并在必要时咨询专业人士的建议,是常重要的。 这款软件为特定的IT任务提供了便利,但也提醒我们在使用时要遵守法律,尊重知识产权,并充分了解潜在风险。谨慎操作,合理利用,才能充分发挥这类工具的效用,同时避免不必要的麻烦。

65,198

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧