原文地址:http://onevcat.com/2013/05/talk-about-warning/

一个有节操的程序员会在乎自己的代码的警告,就像在乎饭碗边上有只死蟑螂那样。 ——@onevcat

重视编译警告

现在编译器有时候会很吵,而编译器给出的警告对开发者来说是很有用的信息。警告不会阻止继续编译和链接,也不会导致程序不能运行,但是很多时候编译器会先你一步发现问题所在,对于Objective-C来说特别如此。Clang不仅对于明显的错误能够提出警告(比如某方法或者接口未实现),也能对很多潜在可能的问题做出提示(比如方法已经废弃或者有问题的转换),而这些问题在很多时候都可能成为潜在的致命错误,必须加以重视。

像Ruby或者PHP这样的动态语言没有所谓的编译警告,而C#或者Java这类语言的警告很多都是不得不照顾的废弃方法什么的,很多开发者已经习惯于忽略警告进行开发。OC由于现在由苹果负责维护,Clang的LLVM也同时是苹果在做,可以说从语言到编译器到SDK全局都在掌握之中,因此做OC开发时的警告往往比其他语言的警告更有参考价值。打开尽可能多的警告提示,并且在程序开发中尽量避免生成警告,对于构建一个健壮高效的程序来说,是必须的。

在Xcode中开启额外警告提示

Xcode的工程模板已经为我们设置开启了一些默认和常用的警告提示,这些默认设置为了兼容一些上年头的项目,并没有打开很多,仅是指对最危险和最常见的部分进行了警告。这对于一个新项目来说这是不够用的(至少对我来说是不够用的),在无数前辈大牛的教导下,首先要做的事情就是打开尽可能多的警告提示。

最简单的方法是通过UI来打开警告。在Xcode中,Build Setting选项里为我们预留了一些打开警告的开关,找到并直接勾选相应的选项就可以打开警告。大部分时间里选项本身已经足够能描述警告的作用和产生警告的时机,如果不是很明白的话,在右侧的Quick Help面板里有更详细的说明。对于OC开发来说特有的警告都在Apple LLVM compiler 4.2 - Warnings - Objective C一栏中,不管您是不是决定打开它们,都是值得花时间看一看加以了解的,因为它们都是写OC程序时最应该避免的情况。另外几个Apple LLVM compiler 4.2 - Warnings - …(All languages和C++)也包含了大量的选项,以方便控制警告产生。

当然在UI里一个一个点击激活警告虽然简单,但每次都这样来一回是一种一点也不有趣的做法,特别是在你已经了解它们的内容并决定打开它们的时候。在编译选项中加入合适的flag能够打开或者关闭警告:在Build Setting中的Other C Flags里添加形似-W...的编译标识。你可以在其中填写任意多的-W...以开关某些警告,比如,填写为-Wall -Wno-unused-variable即可打开“全部”警告(其实并不是全部,只是一大部分严重警告而已),但是不启用“未使用变量”的警告。使用-W...的形式,而不是在UI上勾选的一大好处是,在编译器版本更新时,新加入的警告如果包含在-Wall中的话,不需要对工程做任何修改,新的警告即可以生效。这样立即可以察觉到同一个工程由于编译器版本更新时可能带来的隐患。另外一个更重要的原因是..Xcode的UI并没有提供所有的警告 =_=||..

刚才提到的,需要注意的是,-Wall的名字虽然是all,但是这真的只是一个迷惑人的词语,实际上-Wall涵盖的仅只是所有警告中的一个子集。在StackExchange上有一个在Google工作的Clang开发者进行的回答,其中解释了有一些重要的警告组:

  • -Wall 并不是所有警告。这一个警告组开启的是编译器开发者对于“你所写的代码中有问题”这一命题有着很高的自信的那些警告。要是在这一组设定下你的代码出现了警告,那基本上就是你的代码真的存在严重问题了。但是同时,并不是说打开Wall就万事大吉了,因为Wall所针对的仅仅只是经典代码库中的为数不多的问题,因此有一些致命的警告并不能被其捕捉到。但是不论如何,因为Wall的警告提供的都是可信度和优先级很高的警告,所以为所有项目(至少是所有新项目)打开这组警告,应该成为一种良好的习惯。
  • -Wextra 如其所名,-Wextra组提供“额外的”警告。这个组和-Wall组几乎一样有用,但是有些情况下对于代码相对过于严苛。一个很常见的例子是,-Wextra中包含了-Wsign-compare,这个警告标识会开启比较时候对signed和unsigned的类型检查,当比较符两边一边是signed一边是unsigned时,产生警告。其实很多代码并没有特别在意这样的比较,而且绝大多数时候,比较signed和unsigned也是没有太大问题的(当然不排除会有致命错误出现的情况)。需要注意,-Wextra-Wall是相互独立的两个警告组,虽然里面打开的警告标识有个别是重复的,但是两组并没有包含的关系。想要同时使用的话必须在Other C Flags中都加上
  • -Weverything 这个是真正的所有警告。但是一般开发者不会选择使用这个标识,因为它包含了那些还正在开发中的可能尚存bug的警告提示。这个标识一般是编译器开发者用来调试时使用的,如果你想在自己的项目里开启的话,警告一定会爆棚导致你想开始撞墙..

关于某个组开启了哪些警告的说明,在GCC的手册中有一个参考。虽然苹果现在用的都是LLVM了,但是这部分内容应该是继承了GCC的设定。

控制警告,局部加入或关闭

Clang提供了我们自己加入警告或者暂时关闭警告的办法。

强制加入一个警告:

//Generate a warning
#pragma message "Warning 1" //Another way to generate a warning
#warning "Warning 2"

两种强制警告的方法在视觉效果上结果是一样的,但是警告类型略有不同,一个是-W#pragma-messages,另一个是-W#warnings。对于第二种写法,把warning换成error,可以强制使编译失败。比如在发布一些需要API Key之类的类库时,可以使用这个方法来提示别的开发者别忘了输入必要的信息。

//Generate an error to fail the build.
#error "Something wrong"

对于关闭某个警告,如果需要全局关闭的话,直接在Other C Flags里写-Wno-...就行了,比如-Wextra -Wno-sign-compare就是一个常见的组合。如果相对某几个文件开启或禁用警告,在Build Phases的Compile Source相应的文件中加入对应的编译标识即可。如果只是想在某几行关闭某个警告的话,可以通过临时改变诊断编译标记来抑制指定类型的警告,具体如下:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable" int a; #pragma clang diagnostic pop

如果a之后没有被使用,也不会出未使用变量的警告了。对于想要抑制的警告类型的标识名,可以在build产生该警告后的build log中看到。Xcode中的话,快捷键Cmd+7然后点击最近的build log中,进入详细信息中就能看到了。

我应该开启哪些警告提示

个人喜好(代码洁癖)不同,会有不同的需求。我的建议是对于所有项目,特别是新开的项目,首先开启-Wall-Wextra,然后在此基础上构建项目并且避免一切警告。如果在开发过程中遇到了某些确实无法解决或者确信自己的做法是正确的话(其实这种情况,你的做法一般即使不是错误的,也会是不那么正确的),可以有选择性地关闭某些警告。一般来说,关闭的警告项目不应该超过一只手能数出来的数字,否则一定哪儿出问题了..

是否要让警告等于错误

一种很常见的做法和代码洁癖是将警告标识为错误,从而中断编译过程。这让开发者不得不去修复这些警告,从而保持代码干净整洁。在Xcode中,可以通过勾选相应的Treat Warnings as Errors来开启,或者加入-Werror标识。我个人来说不喜欢使用这个设定,因为它总是打断开发流程。很多时候并不可能把代码全写完再编译调试,相反地,我更喜欢写一点就编译运行一下看看结果,这样在中间debug编译的时候会出现警告也不足为奇。另外,如果做TDD开发时,也可能会有大量正常的警告出现,如果有警告就不让编译的话,开发效率可能会打折扣。一个比较好的做法是只在Release Build时将警告视为错误,因为Xcode中是可以为Debug和Release分别指定标识的,所以这很容易做到。

另外也可以只把某些警告当作错误,-Werror=...即可,同样地,也可以在-Werror被激活时使用-Wno-error=...来使某些警告不成为错误。结合使用这些编译标识可以达到很好的控制。

谈谈Objective-C的警告 (转)的更多相关文章

  1. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  2. 从一个线上服务器警告谈谈backlog

    缘起 双十一如期而至,此时的我因为在处理客户的一个问题已经陷入了忙碌.突然,不断接到驻场实施发来的反馈,都是相同的反馈--"客户端操作缓慢". 我现在负责的服务器是一台接口服务器, ...

  3. 刨根问底Objective-C Runtime

    http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective%5Bnil%5Dc-runtime-(2)%5Bnil%5D-object-and- ...

  4. iOS开发——项目实战总结&带你看看Objective-C的精髓

    带你看看Objective-C的精髓 1:接口与实现 @interface...@end @implementation...@end @class 接口(头文件) 实现文件 向前引用 注:类别通过增 ...

  5. 转 谈谈android反编译和防止反编译的方法

    谈谈android反编译和防止反编译的方法   android基于java的,而java反编译工具很强悍,所以对正常apk应用程序基本上可以做到100%反编译还原. 因此开发人员如果不准备开源自己的项 ...

  6. 谈谈C语言的数据类型

    本文摘要: 本文主要讲述C语言中的数据类型,从基本的数据类型到派生的数据类型,从int ,char ,float double ....到指针,数组,函数,指向指针的指针,指向数组的指针,指向函数的指 ...

  7. iOS开发——新特性OC篇&Objective新特性

    Objective新特性 Overview 自 WWDC 2015 推出和开源 Swift 2.0 后,大家对 Swift 的热情又一次高涨起来,在羡慕创业公司的朋友们大谈 Swift 新特性的同时, ...

  8. Objective中的协议(Protocol)

    Objective中的协议(Protocol) 作用: 专门用来声明一大堆方法. (不能声明属性,也不能实现方法,只能用来写方法的声明). 只要某个类遵守了这个协议.就相当于拥有这个协议中的所有的方法 ...

  9. Python 2.7 cython cythonize py 编译成 pyd 谈谈那些坑

    Python 2.7 cython cythonize py 编译成 pyd 谈谈那些坑 前言 基于 python27 的 pyc 很容易被反编译,于是想到了pyd,加速运行,安全保护 必要准备 安装 ...

随机推荐

  1. ubuntu使用ssh登入不执行.bashrc解决方法

    解决方法,可以直接输入 bash即可. 理解 bashrc 和 profile linux bashrc profile SEP 30TH, 2011 BY SUNTEYA 在一般的 linux 或者 ...

  2. HTTPS-能否避免流量劫持

    流量劫持是什么? EtherDream在一篇科普文章<>中详细介绍了流量劫持途径和方式. 流量劫持是一种古老的攻击方式,比如早已见惯的广告弹窗等,很多人已经对此麻木,并认为流量劫持不会造成 ...

  3. 锋利的jQuery-7--一个$.fn.color插件的编写过程

    编写一个设置和获取元素的color的插件: 首先实现第一个功能,设置: ;(function($){ $.fn.extend({ color:function(value){ return this. ...

  4. 史上最浅显易懂的Git分布式版本控制系统教程

    从零起步的Git教程,让你无痛苦上手世界上最流行的分布式版本控制系统Git! 既然号称史上最浅显易懂的Git教程,那这个教程有什么让你怦然心动的特点呢? 首先,本教程绝对面向初学者,没有接触过版本控制 ...

  5. hdu1114 Piggy-Bank (DP基础 完全背包)

    链接:Piggy-Bank 大意:已知一只猪存钱罐空的时候的重量.现在的重量,已知若干种钱的重量和价值,猪里面装着若干钱若干份,求猪中的钱的价值最小值. 题解: DP,完全背包. g[j]表示组成重量 ...

  6. acdream.Bet(数学推导)

    Bet Time Limit:1000MS     Memory Limit:64000KB     64bit IO Format:%lld & %llu Submit Status Pra ...

  7. FineUI第五天---按钮控件

    按钮控件 <x:Button runat="server" ID="按下" Text="按下"></x:Button> ...

  8. Window_搭建SVN服务器

    http://wenku.baidu.com/link?url=614FLi_VlhiJpyG5bq8JcwFBHroMjsV3FvBDzyyn0snZ85jbWx7xh-RPJdH7stxlgM9i ...

  9. Linux文件与目录常用命令

    目录常用命令: cd:切换目录 pwd:显示当前目录 mkdir:新建一个目录 rmdir:删除一个空的目录 ## cd 命令几种常用方法: cd ~username 切换到用户username的主文 ...

  10. c++ builder xe2 (Embarcadero rad studio) 远程调试 同样适用于 delphi 远程调试 教程

    转载:http://www.cnblogs.com/zhangdongsheng/p/3411056.html 每次要远程调试的时候都要看半天的xe2英文帮助文档,今天正好有点时间,把它写下来. 一. ...