是否有必要遵循该标准,并采用C标准?


17

Stack Overflow上有一些非常有经验的人,他们总是谈论C标准。人们似乎不喜欢非便携式解决方案,即使他们为我工作。好的,我知道需要遵循该标准,但是它不会给程序员的创造力带来束缚吗?

遵循标准有什么具体好处?特别是因为编译器可能会稍微不同地实现标准。


7
您能否阐明“标准”的含义?您是说不实现标准未定义的行为吗?还是不使用扩展/编译器功能?还是样式约定?
ikh

1
@ikh他正在考虑ISO C标准(C90,C99,C11)。
Aseem Bansal

9
这就是说用英语语法和词汇用英语写作或说话会给您的创造力带来束缚。当然,人们可以通过破坏规则来做奇妙的事情,以一致性为代价,但是您仍然可以遵循英语的“标准”来撰写数百万本有创意的书。
Avner Shahar-Kashtan

您是否可以添加一个示例“即使他们为我工作,人们似乎也不喜欢非便携式解决方案”?
2013年

1
@PHIfounder为了解决最后一种情况,您可以省略main的返回值,它隐式返回0 :)
Daniel Gratzer

Answers:


45

坚持标准是一件好事,有几个原因。

  1. 被锁定在编译器中很难。您完全由一群拥有自己议程的开发人员所左右。它们显然并不能解决您的问题,但是如果您的编译器开始滞后于优化,新功能,安全修复等,那就太糟糕了;你被困住了。在极端情况下,一些公司必须开始修补他们依赖的任何工具。当有其他工作工具时,这是巨大的金钱和时间浪费。

  2. 被锁定在平台上会更难。如果您在Linux上开发软件并想切换到Windows,因为您意识到自己的市场确实存在,那么您将有一点时间更改代码中的每个非便携式黑客,以使其发挥出色同时使用GCC和MSVC。如果您的核心设计有几个类似的基础,那么祝您好运!

  3. 向后不兼容的更改最困难。该标准永远不会破坏您的代码(忽略python)。但是,一些随机的编译器作者可能会决定,确实不值得为此麻烦的特定附加组件,因此放弃它。如果您碰巧依赖它,那么您将停留在最后使用的任何过时的旧版本上。

因此,遵循标准的首要信息使您更加灵活。您的语言肯定会更有限,但您的语言会更多

  • 图书馆
  • 支持(人们知道标准,而不是每种复杂的编译器特有的技巧)
  • 可用平台
  • 成熟的工具
  • 安全性(面向未来)

这是一个微妙的平衡,但是完全忽略该标准绝对是一个错误。我倾向于组织我的C代码以依赖可能以非便携式方式实现的抽象,但是我可以透明地移植而无需更改依赖抽象的所有内容。


+1公平:),谢谢...我对编译器稍微偏离标准的方式感到非常困惑,使我对严格遵循该标准持怀疑态度,需要了解其优缺点,并清楚地识别了这些标准。
0decimal0

6
未定义的行为可能也很糟糕。如果您不严格遵循标准,使用c可以很容易地进入UB。
CodesInChaos

@CodesInChaos同意的,未定义的行为一方面很棒,因为它允许进行一些疯狂的优化,但另一方面也对其进行调试...
Daniel Gratzer 2013年

6

该标准是您与编译器之间的一种“合同”,它定义了程序的含义。作为程序员,我们经常对语言的工作方式有一个确定的思维模式,而这种思维模式通常与标准不符。(例如,C程序员经常将指针视为大致“表示内存地址的整数”,因此,假定对可能使用表示内存的整数执行的指针执行任何算术/转换/操作是安全的。这个假设与标准不符;实际上,它对指针的操作施加了非常严格的限制。)

那么,遵循标准而不是您自己的心理模型有什么好处?

简而言之,那就是标准是正确的,而您自己的思维模式是错误的。您的思维模型通常是简化的视图,说明在通常情况下禁用所有编译器优化后,事情如何在自己的系统上运行;编译器供应商通常不努力遵循它,尤其是在优化方面。(如果您不履行合同的最后期限,则您将无法期望编译器发生任何特定行为:垃圾回收,垃圾回收。)

人们似乎不喜欢非便携式解决方案,即使他们为我工作。

最好说“即使他们似乎为我工作”。除非您的编译器专门记录了给定的行为将起作用(即:除非您使用的是由标准的适当的标准加上编译器文档组成的丰富标准),否则您将不知道它确实有效,或者它确实可靠。例如,有符号整数溢出通常会导致在许多系统上进行包装(因此INT_MAX+1通常是INT_MIN)-除非编译器“知道”有符号整数算术永远不会在(正确的)C程序中溢出,并且经常基于此“知识”。


1
您可以使用进行编译-fwrapv,然后使用略有不同的非标准语言,该语言总是包裹有符号整数算术。
user253751

@immibis:在编写C89时,根据其基本原理文档,大多数当代编译器都为整数溢出定义了无声环绕语义。在许多情况下,对整数溢出发生的情况进行某种形式的保证可能会使代码比没有此类保证的情况下的代码效率更高,尤其是在保证范围不至于要求精确的包装行为的情况下[精确可以使用无符号数学来模拟包装行为,但是较宽松但仍足以满足要求的语义可以允许使用更有效的代码。
超级猫

@immibis:令人遗憾的是,修正主义者无法说服人们,在某些平台上(几乎在某些情况下100%一致)在编译器中几乎一致实现的行为从未在这些平台上成为“标准”,因为由于必须避免此类行为而导致的效率损失将无法通过编译器通过吊销它们来实现的任何“优化”来弥补。
超级猫

4

我了解需要遵循该标准,但是这是否会给程序员的创造力带来束缚?不同的编译器遵循标准的方式仍然存在一些差异。例如,我可以编写一个行之有效的代码,在性能和速度上都非常好,即所有方面都很重要,但仍然不一定严格遵循标准。

否。标准告诉我们可以做什么。如果未指定,则您处于未定义的行为范围内,然后所有选择都关闭了-该程序可以自由执行任何操作。


由于您提到了void main()vs的特定示例int main(),因此我可以改善答案。

void main()不是主要功能的标准声明。它可以通过扩展在某些编译器上工作,但它依赖于实现。即使工作正常,也必须检查它是否满足您的要求。问题是,编译器开发人员可能决定void main()在下一个编译器版本中删除它,从而破坏您的应用程序。

另一方面,该标准明确定义了main as的签名,int main()并说明了应该做什么。


另一方面,有些东西没有在标准中定义。然后,可以应用另一个标准(例如POSIX)。最好的示例可能是在c ++ 03中实现线程,因为c ++ 03标准程序是1线程的。在这种情况下,您将不得不使用依赖于平台的库或诸如boost之类的东西。


4
编译器所做的所有非标准操作都不是未定义的行为,从确定性和故意的意义上来说,编译器扩展已得到良好定义。UB不是。
Daniel Gratzer

@jozefg询问的方式-很明显,OP认为UB的实现方式。例如,线程未在c ++ 03中定义。
2013年

1
@deworde:该评论已从答案中删除。
凯文

@jozefg如果特定的编译器始终包装带符号的整数,则可以将其视为未记录的语言扩展。(当然,不
公开

-6

如果您的项目是关于特殊项目的,则不要遵循规则,例如gov项目或军方项目,但是如果您是在谈论开源或具有分布式团队的大型项目,则需要遵循规则。


2
如果没有任何解释,那么如果有人发表相反的意见,此答案可能会毫无用处。例如,如果有人发布诸如“如果您的项目涉及特殊项目,例如政府项目或军方项目,则遵循规则,但如果您谈论的是开放源代码,则无需遵循规则……”,这个答案将如何帮助读者挑出两个相反的观点?考虑将其编辑为更好的形状
gna

2
Uknown:您会惊讶地发现政府项目中有多少标准...
Deer Hunter
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.