[编程好习惯] 恰当使用goto语句

转自:http://yunli.blog.51cto.com/831344/248828

goto 语句在C/C++语言中可谓是“臭名昭著”,乃至有的书(或公司的编程规范)提出禁用goto语句的说法。其结果就是,造成有的程序员一看到goto语句 在某程序中被使用,就本能地认为这个程序写得很“垃圾”。此外,也使得有些程序员因为使用了goto语句而觉得自己很不专业。其实,凡事都不能太偏 激,goto语句运用得好能大大地简化程序,以及提高程序的可读性和可维护性。在开始示例其好处之前,先用一些统计数据来说明goto语句并没有因为“臭 名昭著”而被抛弃,这些统计数据可能并不是百分之百的精确,但很具有说服力。对于操作系统,Linux-2.6.21内核使用了20,333个goto语 句,VxWorks-6.2则使用了9142个,最后941个goto语句被运用到了rtems-4.9.2中;另外,glibc-2.9库使用了 1750个goto语句。所有这些统计数据都表明,goto语言并没有想象的那样可怕而招到禁用,其关键在于 —— 恰当地运用它。



图1是一个没有采用goto语句编写的函数,其中存在多处出错处理的代码,比如113~115行、120~122行和126~129行。采用这种分布式的出错处理,很容易出现遗漏释放前面已经分配的资源,从而造成资源泄漏问题。如果采用goto语句,则能取得更好的效果。

example.c

00097: int queue_init (queue_t _pp_queue, int _size)

00098: {

00099: pthread_mutexattr_t attr;

00100: queue_t queue;

00101:

00102: queue = (queue_t
) malloc(sizeof(queue_t));

00103: if (0 == queue) {

00104: return -1;

00105: }

00106: _pp_queue = queue;

00107:

00108: memset (queue, 0, sizeof (
queue));

00109: queue->size_ = size;

00110:

00111: pthread_mutexattr_init (&attr);

00112: if (0 != pthread_mutex_init(&queue->mutex
, &attr)) {

00113: pthread_mutexattr_destroy (&attr);

00114: free (queue);

00115: return -1;

00116: }

00117:

00118: queue->messages_ = (void
) malloc (queue->size_ * sizeof (void ));

00119: if (0 == queue->messages_) {

00120: pthread_mutexattr_destroy (&attr);

00121: free (queue);

00122: return -1;

00123: }

00124:

00125: if (0 != sem_init(&queue->sem_put_, 0, queue->size_)) {

00126: free (queue->messages_);

00127: pthread_mutexattr_destroy (&attr);

00128: free (queue);

00129: return -1;

00130: }

00131:

00132: pthread_mutexattr_destroy (&attr);

00133:

00134: return 0;

00135: }图1
图2是采用goto语句所编写的另一个版本,与不采用goto语句的版本相比,程序更加的简单,且在出错处理的地方大都使用goto语句跳转到程序的末尾进行处理。goto语句除了可以用在这里所示例的出错处理中,还可以用在其它的程序逻辑中以简化程序并提高阅读性。
example.c

00053: int queue_init (queue_t
_pp_queue, int _size)

00054: {

00055: pthread_mutexattr_t attr;

00056: queue_t
queue;

00057:

00058: queue = (queue_t ) malloc(sizeof(queue_t));

00059: if (0 == queue) {

00060: return -1;

00061: }

00062:
pp_queue = queue;

00063:

00064: memset (queue, 0, sizeof (queue));

00065: queue->size_ = size;

00066:

00067: pthread_mutexattr_init (&attr);

00068: if (0 != pthread_mutex_init(&queue->mutex
, &attr)) {

00069: goto error;

00070: }

00071:

00072: queue->messages_ = (void
) malloc (queue->size_ * sizeof (void ));

00073: if (0 == queue->messages
) {

00074: goto error;

00075: }

00076:

00077: if (0 != sem_init(&queue->sem_put_, 0, queue->size_)) {

00078: goto error1;

00079: }

00080:

00081: pthread_mutexattr_destroy (&attr);

00082:

00083: return 0;

00084:

00085: error1:

00086: free (queue->messages_);

00087: error:

00088: pthread_mutexattr_destroy (&attr);

00089: free (queue);

00090: return -1;

00091: }图2
使用goto语句时需要注意以下原则:

1) 不要过份地使用。比如图2中的60行就没有采用goto语句跳到程序的最后面,之所以这里不使用goto是为了阅读方便。因为程序此时还没有分配资源,所 以直接返回显得更加的直接了当。还有就是,在这个函数中如果存在使用goto语句都意味着出错了且需要释放资源。如果将60行的语句也改为goto就破坏 了这个函数中使用goto语句的一致性。

2) 不要让goto语句形成一个环。使用goto语句应形成一条线,从一点跳到另一点。当然,如果goto语句的使用没有破坏可读性,那可以适当的考虑打破这一原则。

原文链接: https://www.cnblogs.com/zjfdbz/archive/2013/03/06/2945909.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/79866

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午7:15
下一篇 2023年2月9日 下午7:16

相关推荐