ios用的什么编译器编译
Between projects I spent time researching the root causes of high-cost bugs in large game teams. The findings lead us to question basic C++ language features and patterns. This post covers obfuscation issues from a technical leadership POV. The background research to these ideas is covered in “How to write fewer bugs”.
在两个项目之间,我花时间研究了大型游戏团队中高成本漏洞的根本原因。 这些发现使我们对基本的C ++语言功能和模式提出了质疑。 这篇文章涵盖了技术领导POV的混淆问题。 “如何编写更少的错误”中介绍了对这些想法的背景研究。
What do your team’s Coding Standards look like? Maybe they are based on a common or open standard? Maybe they define camelCase variable names for readability? Maybe they define source code doxy-mentation formatting for maintenance? Maybe none of this matters? Do they actually help? Do you have fewer bugs or less misunderstanding? Your coding standards might tick all of your OCD coding boxes but do they actually help the team function in a demonstrably better way?
您的团队的编码标准是什么样的? 也许它们基于通用或开放标准? 也许他们定义了camelCase变量名称以提高可读性? 也许他们定义了用于维护的源代码doxy-mentation格式? 也许这都不重要吗? 他们真的有帮助吗? 您有更少的错误或更少的误解吗? 您的编码标准可能会打勾您所有的OCD编码框,但它们实际上是否以明显更好的方式帮助团队运作?
When I wrote the coding standard for Onrush we had a clean sheet. No prior code to worry about. The standard did not include anything about where our brackets should be. Nothing about camelCase or underscore naming conventions. Nothing about documentation formatting. In fact, we didn’t even call it a coding standard. We sat down and we discuss what we really cared about in our code. We wanted higher quality. For us and our games, this meant more time on iteration, less time on rectification. Higher performance and lower bug count.
当我为Onrush编写编码标准时,我们有了一个清晰的表。 无需担心之前的代码。 该标准未包含有关括号应放在何处的任何内容。 没有关于camelCase或下划线的命名约定。 与文档格式无关。 实际上,我们甚至没有称其为编码标准。 我们坐下来,讨论我们在代码中真正关心的内容。 我们想要更高的质量。 对于我们和我们的游戏而言,这意味着更多的迭代时间,更少的修正时间。 更高的性能和更少的错误计数。
We wrote our Coding Tenets. The coding principals we care most deeply about.
我们写了我们的编码原则 。 我们最关心的编码原则。
The Coding Tenets contained statements like: Compile times and link times are a function of code quality. Write assertive code and not defensive code. Overloading is obfuscation. Name functions and classes so that high-level code reads like pseudocode. Given readable code documentation is largely useless. Document concepts, ideas and reasoning, do not document the code. The compiler is a tool for validating assumptions.
编码原则包含如下语句:编译时间和链接时间是代码质量的函数。 编写断言而不是防御性代码。 重载是一种混淆。 命名函数和类,以便高级代码像伪代码一样读取。 给定可读的代码文档在很大程度上是没有用的。 记录概念,想法和推理不记录代码。 编译器是用于验证假设的工具。
We allowed people to have their own coding style as long as it didn’t contradict any of the Coding Tenets. This resulted in a code base that was highly uniform in functional approach and flexible in styling. This flexible styling didn’t matter. It didn’t affect readability or understanding because the core tenets underpinned everything.
只要不与任何编码原则相抵触,我们就允许人们拥有自己的编码风格。 这导致了代码库的功能方法高度统一,样式灵活。 这种灵活的样式并不重要。 它不影响可读性或理解性,因为核心原则是一切的基础。
If you haven’t tried, stop writing Physics::Simulation.Update(dt) and start writing updateThePhysicsSimulationForThisTimeStep(dt). When I started writing descriptive function names I started thinking about the data and the transformations being applied. The former is obtusely object oriented. The latter is choosing a function name which describes operations and data names which describe information. Aim for high-level code which clearly describes the functional operations. That clearly shows the data dependencies. Aim for high-level code which does not need documentation.
如果您尚未尝试过,请停止编写Physics :: Simulation.Update(dt),然后开始编写updateThePhysicsSimulationForThisTimeStep(dt)。 当我开始编写描述性的函数名称时,我开始考虑数据和所应用的转换。 前者是钝的面向对象。 后者是选择描述操作的函数名称和描述信息的数据名称。 旨在提供清晰描述功能操作的高级代码。 这清楚地显示了数据依赖性。 瞄准不需要文档的高级代码。
When coding C++ the compiler is my best friend. She scrutinises every line of code. She encodes my thoughts into executable code. She shows me my assumptions and misunderstandings. She lays out my human shortcomings. But, the compiler is not a mind reader. She does not possess psychic powers. Only unwavering diligence to produce correct code.
在编写C ++时,编译器是我最好的朋友。 她仔细检查了每一行代码。 她将我的想法编码为可执行代码。 她向我展示了我的假设和误解。 她提出了我人类的缺点。 但是,编译器不是头脑读者。 她没有心理能力。 只有坚定不移地努力,才能产生正确的代码。
The compiler applies the strict rules of the C++ language to verify the correctness of my code. Although in this respect the C++ language is not exact. C++ has many ways to be inexact. Many ways to ask the compiler to make assumptions. If I have learnt one thing over the years it is this: making assumptions will always get you into trouble.
编译器应用C ++语言的严格规则来验证我的代码的正确性。 尽管在这方面,C ++语言并不精确。 C ++有许多不精确的方法。 要求编译器做出假设的多种方法。 如果多年来我已经学到一件事,那就是:做出假设总是会让您陷入麻烦。
As C++ continues to grow and bloat to the size of a dwarf star, it easy to overlook the fundamentals. Are these basic programming concepts working for or against your team? The examples and comments below are specifically about C++ but apply to many modern languages.
随着C ++的不断增长并膨胀到矮小的恒星大小,很容易忽略基本原理。 这些基本的编程概念对您的团队有利还是不利? 下面的示例和注释专门针对C ++,但适用于许多现代语言。
So let’s start at the beginning with polymorphism. Introduced in 1983 when ‘C with classes’ was renamed to C++. Polymorphism allows many function or methods to have the same name. The compiler will select the correct function using the types of the parameters. There is however a fundamental issue here. When is it ever good to have different things with the same name?
因此,让我们从多态开始。 在1983年引入,当时“带有类的C”重命名为C ++。 多态性允许许多函数或方法具有相同的名称。 编译器将使用参数类型选择正确的函数。 但是,这里存在一个基本问题。 什么时候拥有相同名字的不同事物会变得更好?
Consider this typical C++ 101 example where we have variants of a FileWrite function or method.
考虑这个典型的C ++ 101示例,其中有FileWrite函数或方法的变体。
// Simple polymorphic file write functions for int, short and char
bool FileWrite(int i);
bool FileWrite(short f);
bool FileWrite(char c);
This seems convenient. I just call FileWrite with any type and the compiler will sort it out. The compiler has perfect knowledge of the code and will pick the functions needed to compile without errors. The process is deterministic and foolproof.
这似乎很方便。 我只是用任何类型调用FileWrite,编译器会对其进行排序。 编译器对代码有充分的了解,并会选择编译所需的功能而不会出错。 这个过程是确定性的并且是万无一失的。
Unfortunately not. The compiler may have perfect knowledge of the code, but the compiler has zero knowledge of intent. I am telling the compiler to assume the code I type correctly implements my intent. Now I know for a fact that I am not always correct, 20 years of programming has taught me this. With this convenience, I have lost an important opportunity for the compiler to find errors in my code and this will eventually lead to a difficult to find runtime error.
不幸的是没有。 编译器可能对代码有完全的了解,但是编译器对意图的了解却为零。 我告诉编译器假定我键入的代码正确实现了我的意图。 现在,我知道我并非总是正确的事实,二十年来的编程教会了我这一点。 有了这种便利,我就失去了编译器在代码中查找错误的重要机会,最终将导致难以发现运行时错误。
As a Technical Director or Technical Lead, my primary concern is getting the programming team to work efficiently together. The larger the team the harder a problem this becomes. Here is a typical development situation using the simple code above.
作为技术主管或技术负责人,我主要关心的是使编程团队有效地合作。 团队越大,问题就越难解决。 这是使用上面的简单代码的典型开发情况。
// Simple example structure with three int members.
struct Brain
{
int humor;
int intelligence;
int empathy;
}
ai_brain.cpp:
ai_brain.cpp:
// Example usecase using polymorphic file functions
void SaveGame(Brain& brain)
{
FileWrite(brain.humor);
FileWrite(brain.intelligence);
FileWrite(brain.empathy);
}
void LoadGame(Brain& brain)
{
FileRead(brain.humor);
FileRead(brain.intelligence);
FileRead(brain.empathy);
}
Ok still C++ 101. In the programming team, Tom is working on the AI and Jerry is working on the Save Game. Everyone on the team is busy working for the next milestone build. Suddenly the game is crashing during the Loading Phase and the team a blocked. The milestone is looming and everyone looks at Jerry to fix the crash.
好的还是C ++101。在编程团队中,汤姆(Tom)正在研究AI,杰里(Jerry)正在研究Save Game。 团队中的每个人都在为下一个里程碑构建而忙。 突然,游戏在载入阶段崩溃了,并且该团队被封锁了。 里程碑迫在眉睫,所有人都在看着Jerry修复崩溃。
The problem is Jerry has not submitted code today. Jerry starts to investigate the problem. Source control shows that no changes have been made to the Save Game module files today. The debugger shows the crash in the Pickup code. Another search of the SCM shows no changes in the Pickup module today. The input file stream for the saved game data appears to be corrupt. Jerry sighs and takes a sip of coffee and continues to investigate.
问题是Jerry今天尚未提交代码。 杰里开始调查问题。 源代码管理显示,今天尚未对“保存游戏”模块文件进行任何更改。 调试器在Pickup代码中显示崩溃。 对SCM的另一次搜索显示,今天的代答模块没有任何更改。 保存的游戏数据的输入文件流似乎已损坏。 杰里叹了口气,喝了一口咖啡,继续调查。
After some time the Jerry finds the change which caused the problems in the AI code and goes to talk to Tom.
一段时间后,Jerry发现了导致AI代码出现问题的更改,并与Tom进行了交谈。
// Breaking changes causing **action at a distance**
struct Brain
{
<< old
int humor;
int intelligence;
int empathy;
>>> new
short humor;
short intelligence;
short empathy;
=====
}
Jerry explains to Tom that the change above caused the game to crash creating pickups! The change in the size of the members caused the input stream to become misaligned. The first code to fatal error due to bad data was the Pickup module.
杰瑞(Jerry)向汤姆(Tom)解释说,以上更改导致游戏崩溃,导致拾取失败! 成员大小的更改导致输入流未对齐。 由于不良数据而导致致命错误的第一个代码是分拣模块。
It turnouts out that Tom did get a once only crash in the Loading phase. Tom deleted the save game and the errors when away. As Tom was not working anywhere near the loading code he assumed it was a pre-existing error and continued to work. Tom fully tested his code before submitting and all test passed.
事实证明,汤姆在“加载”阶段确实一次崩溃。 汤姆在离开时删除了保存游戏和错误。 由于Tom不在加载代码附近的任何地方工作,因此他认为这是一个预先存在的错误并继续工作。 汤姆在提交之前完全测试了他的代码,并通过了所有测试。
Polymorphism enables “Action At A Distance” in code.
多态性使代码中的“远距离行动”成为可能。
In the simple example above the compiler started generating different executable code in the LoadGame and SaveGame functions. The code in the LoadGame and SaveGame functions has not changed. None of the code in the Save Game module has changed. The code change in the AI module caused the code in the LoadGame function to mean something different. Then the compiler silently compiled the new LoadGame and SaveGame code without error. The code is technically correct but no longer satisfies the original intent.
在上面的简单示例中,编译器开始在LoadGame和SaveGame函数中生成不同的可执行代码。 LoadGame和SaveGame函数中的代码未更改。 “保存游戏”模块中的代码均未更改。 AI模块中的代码更改导致LoadGame函数中的代码含义不同。 然后,编译器将无提示地静默编译新的LoadGame和SaveGame代码。 该代码在技术上是正确的,但不再满足原始意图。
Consider this alternative.
考虑这个替代方案。
// Strong naming and type safe file write functions
bool FileWriteInt(int i);
bool FileWriteShort(float s);
bool FileWriteChar(char c);
// Example usecase using strong name and typesafe functions
void SaveGame(Brain& brain)
{
FileWriteInt(brain.humor);
FileWriteInt(brain.intelligence);
FileWriteInt(brain.empathy);
}
In this example, the data to be written is explicitly defined by the code. There are no assumptions to be filled in by the compiler. If the types passed to the function are incorrect the compiler will generate an error.
在此示例中,要写入的数据由代码明确定义。 编译器无需填写任何假设。 如果传递给函数的类型不正确,则编译器将生成错误。
We have changed an intermittent data dependent runtime error into a 100% repeatable compile time error.
我们将与数据相关的间歇性运行时错误更改为100%可重复的编译时错误。
Now let’s re-evaluating our scenario with the new code. Tom makes his changes to ai/brain.h and the code fails to compile. It is immediately obvious to Tom that his changes have caused the error. Tom is able to fix the code before submitting the changes. The compiler now discovers the error at compilation, rather than QA or the team finding the bug later.
现在,让我们用新代码重新评估我们的方案。 汤姆对ai / brain.h进行了更改,代码无法编译。 对于汤姆来说,显而易见的是他的更改已引起该错误。 Tom可以在提交更改之前修复代码。 现在,编译器会在编译时发现错误,而不是QA或团队随后发现该错误。
You may be asking why this is an issue? And this deserves an explication.
您可能会问为什么这是一个问题? 这值得说明。
As a single developer in my own project, I have a thorough and in-depth understanding of my code. I can test and iterate with low cost. This simple example of polymorphism shows convenience with very low cost of errors.
作为我自己项目中的单个开发人员,我对我的代码有透彻和深入的了解。 我可以低成本进行测试和迭代。 这个简单的多态示例显示了非常方便的错误成本。
My career as a game developer has been in large teams. When I was at university my lecturers taught OOP, Polymorphism and other clever programming tricks.
我作为游戏开发人员的职业是大型团队。 当我上大学时,我的讲师讲授OOP,多态和其他巧妙的编程技巧。
When I was a junior programmer I would write an overloaded method like above. The tricks are useful to me and I am going to use them in my code. As a senior programmer, I became responsible for bugs in my code. I am more aware of the time cost of maintaining code.
当我是一个初级程序员时,我会写一个像上面那样的重载方法。 这些技巧对我很有用,我将在代码中使用它们。 作为高级程序员,我负责代码中的错误。 我更了解维护代码的时间成本。
As a Technical Lead, I am responsible for bugs in other people’s code. I am involved in planning other people’s work and time estimates to make my team the best. As a Technical Director, I am responsible for the efficiency of the whole programming team. I want the team producing features NOT fixing bugs.
作为技术负责人,我负责别人代码中的错误。 我参与计划其他人的工作和时间估算,以使我的团队变得最好。 作为技术总监,我负责整个编程团队的效率。 我希望团队产生无法修复错误的功能。
In a large game development team of 25, 50, 100 or more programmers, knowledge of the entire code base will vary. I know my code in detail. I know the rest of the code with varying certainty or rather, uncertainty. In a large programming team, I must write code making assumptions to the best of my knowledge. In a larger project, I will make more mistakes than in my own solo project and the cost of these mistakes will be higher.
在由25、50、100或更多程序员组成的大型游戏开发团队中,整个代码库的知识将有所不同。 我详细了解我的代码。 我知道代码的其余部分具有不确定性,甚至不确定性。 在一个大型编程团队中,我必须据我所知编写代码假设。 在一个较大的项目中,与在自己的个人项目中相比,我会犯更多的错误,这些错误的代价会更高。
In the example with Tom and Jerry, Jerry’s choice of polymorphic overloading made it really easy for Tom to introduce a bug. This bug prevented over half the development team from working for nearly 4 hours. In a team of 100 developers this is approximately 200 hours of lost work. That is equivalent to one person working full time for 5 weeks! The convenience of polymorphism to save a small amount of developer effort is completely disproportionate to the impact of the action at a distance bugs that can be introduced.
在Tom和Jerry的示例中,Jerry对多态重载的选择使Tom确实很容易引入错误。 此错误使一半以上的开发团队无法工作近4个小时。 在由100个开发人员组成的团队中,这大约是200个小时的工作损失。 这相当于一个人全职工作5个星期! 多态性节省少量开发人员精力的便利性与该动作的影响完全不成比例,因为这种影响可以引入错误。
To be clear the fault lies with Jerry for making an interface which has a high probability of being used incorrectly. When Tom submitted his changes all tests passed. Tom has done a reasonable amount of testing and has other tasks to move on to. Tom fell into the hole, he did not dig the hole.
显然,Jerry的错误在于制作一个接口的可能性很高,该接口很可能被错误地使用。 汤姆提交变更后,所有测试均通过。 汤姆做了相当多的测试,还有其他工作要做。 汤姆掉进洞里了,他没有挖洞。
Namespaces were introduced in “The Annotated C++ Reference Manual” — 1990 book. Although not widely implemented until around 1995.
命名空间在“带注释的C ++参考手册”(1990年)中引入。 尽管直到1995年左右才广泛实施。
Previously all named objects in a program where globally unique. This caused problems when sharing code between different projects. If names in the shared code clash with the host application then something would have to be renamed. In a large project this could have a significant time impact.
以前,程序中所有命名的对象都是全局唯一的。 在不同项目之间共享代码时,这会引起问题。 如果共享代码中的名称与主机应用程序冲突,则必须重命名某些内容。 在大型项目中,这可能会对时间产生重大影响。
Namespaces which scope the application from external libraries are completely valid and a sensible development choice.
从外部库扩展应用程序范围的命名空间是完全有效的,并且是明智的开发选择。
There is however a tendency for programmers to use excessive namespacing within a project codebase.
但是,程序员倾向于在项目代码库中使用过多的命名空间。
Within a project namespaces enable both
在项目名称空间中,同时启用
— multiple names for the same object.
—同一对象的多个名称。
— multiple objects with the same name.
—具有相同名称的多个对象。
By project codebase I mean specifically the code typed for that project by the team. Not any 3rd party libraries or code from other distinct teams in the same company.
项目代码库是指团队专门为该项目键入的代码。 没有同一个公司中其他不同团队的任何第三方库或代码。
Multiple aliases for the same object makes the code harder to read. Multiple objects with the same name increase assumptions. We are again asking the compiler to assume intent and select the ‘correct’ function or variable. Again as team sizes grow the probability of assumptions leading to errors increases and in large teams there is likely a high cost of failure.
同一对象的多个别名使代码难以阅读。 具有相同名称的多个对象会增加假设。 我们再次要求编译器假定意图并选择“正确”的函数或变量。 同样,随着团队规模的扩大,导致错误的假设的可能性也会增加,在大型团队中,失败的代价可能很高。
The pattern of excessive namespaces is easy to fall into. STL and popular libraries such as Boot are heavily namespaced. These projects are heavily namespaced because in reality they are collections of micro projects into a single library. In these cases namespaces are being used as designed to isolate code from different contributors where refactoring global names would be unnecessarily difficult to orchestrate.
过多名称空间的模式很容易陷入。 STL和流行的库(例如Boot)都具有大量的命名空间。 这些项目具有大量的命名空间,因为实际上它们是微型项目在单个库中的集合。 在这些情况下,使用命名空间的目的是将代码与不同的贡献者隔离开来,在这些地方,重构全局名称将变得非常困难。
However, this pattern is so pervasive that it is commonly copied by developers inside their own code. When writing new code ensuring unique names is easy, the compiler will immediately tell you there is a problem. Inside the team’s codebase, unique naming is good because it avoids assumptions. Using namespaces within the team’s own code creates avoidable assumptions. Which enables the compiler to choose the correct class, function or variable but with the wrong intent/outcome.
但是,这种模式如此普遍,以至于开发人员通常会在自己的代码中复制它。 在编写新代码以确保唯一名称容易时,编译器会立即告诉您存在问题。 在团队的代码库中,唯一命名是好的,因为它避免了假设。 在团队自己的代码中使用名称空间会产生可避免的假设。 这使编译器可以选择正确的类,函数或变量,但意图/结果错误。
math::fast::fpow(2,10)
数学::快速:: fpow(2,10)
math::emulation::fpow(2,10)
数学::仿真:: fpow(2,10)
When using namespaces there are multiple ways to reference the function and there is the possibility of several functions with the same name.
使用名称空间时,有多种方法可以引用该函数,并且可能会有多个具有相同名称的函数。
fpow(2,10)
fpow(2,10)
When reading code, the programmer needs to make an assumption about which specific fpow() function the author intended to be called and which specific fpow() function the compiler will actually choose. There will be no compile-time error if the generated code does not match the intent. These errors will need to be discovered at runtime.
在阅读代码时,程序员需要假设作者打算调用哪个特定的fpow()函数以及编译器将实际选择哪个特定的fpow()函数。 如果生成的代码与意图不匹配,则不会出现编译时错误。 这些错误将需要在运行时发现。
This increases cognitive load. I now need to mentally track the current namespaces which apply to any given block of code. This is a problem which does not scale well with large teams and large code bases.
这增加了认知负担。 现在,我需要在精神上跟踪适用于任何给定代码块的当前名称空间。 这个问题在大型团队和大型代码库中无法很好地扩展。
MathEmuFpow(2,10)
MathEmuFpow(2,10)
MathFastFpow(2,10)
MathFastFpow(2,10)
There is only one way to refer to each of these Fpow functions. No matter where I am in the code, these functions all always have the same unique name. This makes the code easier to read and understand by reducing cognitive load on the programmer. I know the intent of the author and I know the code the compiler will generate.
只有一种方法可以引用每个Fpow函数。 无论我在代码中的什么位置,这些函数都始终具有相同的唯一名称。 通过减少程序员的认知负担,这使得代码更易于阅读和理解。 我知道作者的意图,也知道编译器将生成的代码。
Namespaces have valid use cases for containing external code which you will not need to modify and in many cases not be able to modify. As such I will always put my projects inside a containing namespace. This is a courtesy to other teams and programmers who might need use this code in the future. Within projects, namespaces enable poor naming and assumptions and should be used sparingly.
命名空间具有包含外部代码的有效用例 ,您无需修改它们,并且在许多情况下是无法修改的。 这样,我将始终将我的项目放在一个包含名称空间中。 这是对将来可能需要使用此代码的其他团队和程序员的礼貌。 在项目中,名称空间会导致不良的命名和假设,因此应谨慎使用。
The C++11 standard introduced auto along with a host of other convenience features. Unfortunately auto is yet another compiler assumption feature that tells the compiler to assume the code I have written is correct. The compiler must now choose whatever types allow the code to compile. The problem with this is still, I make mistakes.
C ++ 11标准引入了自动功能以及许多其他便利功能。 不幸的是,auto是另一个编译器假设功能,它告诉编译器假设我编写的代码是正确的。 现在,编译器必须选择允许代码编译的任何类型。 问题仍然存在,我会犯错误。
Auto takes the above issues of polymorphic functions and applies this to variables. For polymorphic functions, the compiler can only choose between functions with matching names. Using auto asks the compiler to select ANY type which will make the code compile!
Auto接受上述多态函数问题,并将其应用于变量。 对于多态函数,编译器只能在具有匹配名称的函数之间进行选择。 使用auto会要求编译器选择ANY类型,这将使代码编译!
Auto allows you to write code without understanding the data types.
自动允许您在不了解数据类型的情况下编写代码。
Auto enables action at a distance for variables.
自动启用一定距离的变量操作。
The most common reason I hear for using auto in C++ is to make the code simpler and easier to read. Long complex STL type names are often given as justification for using auto. It is common to typedef long STL type names into convenient shorthand names. Why not skip this step and use auto?
我听说在C ++中使用auto的最常见原因是使代码更简单易读。 长而复杂的STL类型名称通常作为使用auto的理由。 通常将typedef长STL类型名称转换为方便的速记名称。 为什么不跳过此步骤并使用自动?
Making the code simpler is flawed as a supporting argument. Complexity always leads to more complexity. If another system is complicated and difficult to understand, this complexity is not removed by using auto. Using auto is masking the complexity by making shorthand assumptions. (The only way to tackle complexity leaking out of APIs is to refactor the API.)
作为佐证,使代码更简单是有缺陷的。 复杂性总是导致更多的复杂性。 如果另一个系统复杂且难以理解,则不能通过使用auto消除此复杂性。 使用自动通过进行速记假设掩盖了复杂性。 (解决API泄漏的复杂性的唯一方法是重构API。)
If I do not know the type auto will resolve to, then I am not considering all the possible failure cases. If I do know the type auto will resolve to, then I should use that type instead. Using the specific type better encodes my intent. If the compiler gives me an error, then I have learnt that my assumptions about the types being used are incorrect. Using the specific type also protects the code from later refactoring and action at a distance.
如果我不知道auto类型将解析为哪种类型,那么我就不在考虑所有可能的故障情况。 如果我知道是什么类型的汽车将解析为,那么我应该使用该类型来代替。 使用特定类型可以更好地编码我的意图。 如果编译器给我一个错误,则表明我对所使用类型的假设是不正确的。 使用特定类型还可以保护代码免于以后进行重构和远距离操作。
The cost of using auto in a personal project is probably zero. The cost of using auto in a large development team is potentially large and disproportionate to any benefits.
在个人项目中使用auto的成本可能为零。 在大型开发团队中使用汽车的成本可能很大,并且与任何收益都不成比例。
The compiler is my friend and ally in asserting my assumptions during development. Bugs found by the compiler must by definition be fixed before submitting changes.
编译器是我的朋友,也是在开发过程中断言我的假设的盟友。 根据定义,编译器发现的错误必须在提交更改之前进行修复。
By designing my code to generate compiler errors when used incorrectly, I am helping the other programmers on my team.
通过设计代码以在错误使用时生成编译器错误,我正在帮助团队中的其他程序员。
This fits how we programmers work. I type some code and then hit compile in a short and fast iteration loop. I might even be using an IDE which continuously compiles in the background while I type. If the compiler finds my error quickly after typing, the cost to fix is nearly zero.
这符合我们程序员的工作方式。 我输入一些代码,然后在短而快速的迭代循环中进行编译。 我什至可能会使用在键入时在后台连续编译的IDE。 如果编译器在键入后Swift发现我的错误,则修复成本几乎为零。
Large game development teams scale up the impact of bugs. If a team of hundreds cannot work, dev hours are lost at a truly frightening pace. Large game development projects will usually have large QA teams to find bugs. This introduces significant time delays and costs to bug discovery, fix and verification once the bug has been submitted into the build.
大型游戏开发团队扩大了错误的影响。 如果一个数百人的团队无法工作,那么开发时间将以惊人的速度损失。 大型游戏开发项目通常会拥有大型质量检查团队来查找错误。 一旦将错误提交到构建中,这将导致大量的时间延迟以及错误发现,修复和验证的成本。
As a Technical Director, I must put a cost on the shorthand convenience of polymorphic functions, namespace, auto and other basic language convenience functionality. Comparing that to the impact and cost of extra bugs from unchecked assumptions.
作为技术主管,我必须在多态函数,名称空间,自动和其他基本语言便捷功能的速记便利性上付出一些代价。 将其与未经检查的假设所产生的额外错误的影响和成本进行比较。
At university I was taught that the compiler is a tool for translating source code into executable machine code. For a long time in my programming career I focused on the tech and the optimisation. I thought I knew how to use the compiler to generate the best code, but I was missing the bigger picture.
在大学里,我被告知编译器是一种将源代码转换为可执行机器代码的工具。 在我的编程生涯中很长一段时间,我一直专注于技术和优化。 我以为我知道如何使用编译器来生成最佳代码,但是我却错过了更大的前景。
Writing source code which uses the compiler to validate the author’s intent is every bit as important as generating optimal executable code.
编写使用编译器来验证作者意图的源代码,与生成最佳可执行代码一样重要。
The compiler is actually a tool for translating intent into executable machine code.
编译器实际上是将意图转换为可执行机器代码的工具。
翻译自: https://www.freecodecamp.org/news/why-the-compiler-is-your-best-friend-f165329cb20a/
ios用的什么编译器编译