这种编码风格有什么优势吗?

时间:2011-12-05 05:46:22

标签: c coding-style

|在gestremer matroska demux插件中有这个功能:

gboolean
gst_matroska_demux_plugin_init (GstPlugin * plugin)
{
  /* parser helper separate debug */
  GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
      0, "EBML stream helper class");

  /* create an elementfactory for the matroska_demux element */
  if (!gst_element_register (plugin, "matroskademux",
          GST_RANK_PRIMARY, GST_TYPE_MATROSKA_DEMUX))
    return FALSE;

  return TRUE;
}

现在gst_element_register()

的类型
gboolean            gst_element_register                (GstPlugin *plugin,
                                                         const gchar *name,
                                                         guint rank,
                                                         GType type);
Returns :
    TRUE, if the registering succeeded, FALSE on error

那为什么不用以下方式写呢?

 gboolean
    gst_matroska_demux_plugin_init (GstPlugin * plugin)
    {
      /* parser helper separate debug */
      GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
          0, "EBML stream helper class");

      /* create an elementfactory for the matroska_demux element */
      return gst_element_register (plugin, "matroskademux",
              GST_RANK_PRIMARY, GST_TYPE_MATROSKA_DEMUX))      
    }

5 个答案:

答案 0 :(得分:7)

这是模式的一部分。

if (!some_function(...))
    return false;
if (!other_function(...))
    return false;

return true;

无论是谁编写它都决定不改变模式只是因为只有一个函数调用。最终这是一个品味问题。

答案 1 :(得分:4)

因此代码没有问题。如果有人使用上述任何一个片段,至少我不会受到惩罚。

这些是我认为原因的原因:

  • 最重要的是可读性。现在看部分代码,我知道什么是成功,什么不是。因为可能存在apis,它的行为相反(即使在C中)。
  • 第二个原因发生在测试期间,您想要打印一些日志语句。现在,如果直接返回,则无法记录返回值或任何调试信息。您可以说在释放代码后,应该删除它,但是对于下一个版本,您可能必须再次放置调试语句。所以它就在那里。
  • 第三个原因可能是在开发过程中删除了某些代码。

结论是我在开始时所说的。只要代码易于理解就没关系。关于一些优化收益,我认为这个编译器足够聪明,可以照顾。

答案 2 :(得分:3)

基本上,不是:它使用更多代码和更多指令来说同样的事情。

通常,这表示两件事之一:

  • 对C不太满意的人
  • 代码,其中有人计划用负回报做更多事情,例如,记录错误消息,但没有。

嗯。在这种情况下,它可能表示从Fortran机械翻译的代码。

再次更新

好的,所以这仍然存在争议。这是一个实际的例子。观察该示例与OP示例完全同构:

C代码:

int retcod1() { return 0; }

int ex1(){
    if(retcod1())
        return 0;
    else
        return 1;
}

int ex2() {
    return retcod1();
}

生成的程序集:

这是使用gcc -S -O0生成的代码:

    .file   "code.c"
    .text
.globl retcod1
    .type   retcod1, @function
retcod1:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   retcod1, .-retcod1
.globl ex1
    .type   ex1, @function
ex1:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, %eax
    call    retcod1
    testl   %eax, %eax
    je  .L3
    movl    $0, %eax
    jmp .L4
.L3:
    movl    $1, %eax
.L4:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   ex1, .-ex1
.globl ex2
    .type   ex2, @function
ex2:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, %eax
    call    retcod1
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size   ex2, .-ex2
    .ident  "GCC: (SUSE Linux) 4.5.1 20101208 [gcc-4_5-branch revision 167585]"
    .section    .comment.SUSE.OPTs,"MS",@progbits,1
    .string "ospwg"
    .section    .note.GNU-stack,"",@progbits

为方便起见(假设SO可以处理格式)我已经为两个例程生成了代码并将它们并排放置。注意第二个例子显着更短。

.globl ex1                           .globl ex2                       
    .type   ex1, @function          .type   ex2, @function   
ex1:                                 ex2:                             
.LFB1:                               .LFB2:                           
    .cfi_startproc                  .cfi_startproc           
    pushq   %rbp                    pushq   %rbp             
    .cfi_def_cfa_offset 16          .cfi_def_cfa_offset 16   
    movq    %rsp, %rbp              movq    %rsp, %rbp       
    .cfi_offset 6, -16              .cfi_offset 6, -16       
    .cfi_def_cfa_register 6         .cfi_def_cfa_register 6  
    movl    $0, %eax                movl    $0, %eax         
    call    retcod1                 call    retcod1          
    testl   %eax, %eax              leave                    
    je  .L3                     .cfi_def_cfa 7, 8        
    movl    $0, %eax                ret                      
    jmp .L4                     .cfi_endproc             
.L3:                                 .LFE2:                           
    movl    $1, %eax
.L4:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   ex1, .-ex1

以下是默认优化的示例,即gcc -S

ex1:                                      ex2:                              
.LFB1:                                    .LFB2:                            
    .cfi_startproc                      .cfi_startproc            
    pushq   %rbp                        pushq   %rbp              
    .cfi_def_cfa_offset 16              .cfi_def_cfa_offset 16    
    movq    %rsp, %rbp                  movq    %rsp, %rbp        
    .cfi_offset 6, -16                  .cfi_offset 6, -16        
    .cfi_def_cfa_register 6             .cfi_def_cfa_register 6   
    movl    $0, %eax                    movl    $0, %eax          
    call    retcod1                     call    retcod1           
    testl   %eax, %eax                  leave                     
    je  .L3                         .cfi_def_cfa 7, 8         
    movl    $0, %eax                    ret                       
    jmp .L4                         .cfi_endproc              
.L3:                                      .LFE2:                            
    movl    $1, %eax                    .size   ex2, .-ex2        
.L4:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   ex1, .-ex1
.globl ex2
    .type   ex2, @function

再次,仍然明显缩短。

最后,这是一个例子,这次是完整的优化:

.globl ex1                            .globl ex2                         
    .type   ex1, @function          .type   ex2, @function     
ex1:                                  ex2:                               
.LFB1:                                .LFB2:                             
    .cfi_startproc                  .cfi_startproc             
    movl    $1, %eax                xorl    %eax, %eax         
    ret                             ret                        
    .cfi_endproc                    .cfi_endproc               
.LFE1:                                .LFE2:                             

现在,请注意即使完全优化,仍然也不会像声明的那样创建完全相同的代码。

答案 3 :(得分:1)

除了已经说过的内容之外,由于这是标记的编码风格,因此第一个代码包含一些可能被视为危险的样式。但由于它是编码风格,对它的看法将是主观的。

  • 许多程序员认为多个返回语句是坏的和危险的。
  • 没有跟随大括号的
  • if被许多程序员认为是坏的和危险的风格。 else, else if, for, while, do...while, switch
  • 也是如此

例如,MISRA-C禁止这两种风格(MISRA-C:2004 14.7和14.8)。

(就我个人而言,我不同意这两者中的前者,我认为在很多情况下,多个return语句使代码更具可读性,特别是在发生大量错误检查的函数中,例如解析器等。 )

答案 4 :(得分:1)

我会走出困境直接说是的,后者的风格更优越。那就是:

if (!func())
   return FALSE;
return TRUE;

...假设func()已经返回一个布尔值,上面的样式不如:

return func();

如果前者看起来更具可读性,那么我会恳求那些这样认为可以更好地理解表达的人。如果论证是它更好地强调了这个函数返回TRUE或FALSE,那就意味着读者不会知道func()是如何工作的,那些看这个函数并试图真正理解逻辑的人应该理解只是用猎枪调试随机的代码。

也就是说,这往往会在实践中发生,因为多个开发人员维护代码,因为人们会暂时修改代码以使调试更容易,等等。

我不认为这样的代码存在是一个问题,但我会断言简洁的解决方案更好,因为它保证它至少与更长的一个有效或更多,这意味着我们的额外开销只能希望编译器能够优化掉(我不希望所有编译器的这些分支情况都会发生,即使现在优化编译器有多好)。