簡體   English   中英

這種編碼風格有什么優勢嗎?

[英]Is there any advantage of such 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))      
    }

它是模式的一部分。

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

return true;

編寫它的人決定不改變模式只是因為只有一個函數調用。 最終這是一個品味問題。

因此,代碼沒有問題。 如果有人使用任何提到的片段,至少我不會受到懲罰。

這些是我認為是原因的原因:

  • 最重要的是可讀性。 現在看部分代碼,我知道什么是成功,什么不是。 因為可能存在apis,其行為相反(即使在C中)。
  • 第二個原因發生在測試期間,您想要打印一些日志語句。 現在,如果直接返回,則無法記錄返回值或任何調試信息。 您可以說在釋放代碼后,應該刪除它,但是對於下一個版本,您可能必須再次放置調試語句。 所以它留在那里。
  • 第三個原因可能是在開發過程中刪除了一些代碼。

結論是我在開始時所說的。 只要代碼易於理解就沒關系。 關於一些優化收益,我認為這個編譯器足夠聰明,可以照顧。

基本上,不,它使用更多代碼和更多指令來說同樣的事情。

通常,這表示以下兩種情況之一:

  • 對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:                             

現在,觀察即使完全優化,它仍然不會像斷言那樣創建完全相同的代碼。

除了已經說過的內容,並且由於這是標記的編碼風格,第一個代碼包含一些可能被認為是危險的樣式。 但由於它是編碼風格,對它的看法將是主觀的。

  • 許多程序員認為多個返回語句是壞的和危險的。
  • if沒有跟隨括號被許多程序員認為是壞的和危險的風格。 對於else, else if, for, while, do...while, switch同樣的事情else, else if, for, while, do...while, switch

例如,MISRA-C禁止這兩種風格(MISRA-C:2004 14.7和14.8)。

(就我個人而言,我不同意這兩者中的前者,我認為有很多情況下多個return語句使代碼更具可讀性,特別是在發生大量錯誤檢查的函數中,例如解析器等)

我會走出困境直接說是的,后者的風格更優越。 那是:

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

...並假設func()已經返回一個布爾值,上面的樣式不如:

return func();

如果前者看起來更具可讀性,那么我會懇請那些這樣認為可以更好地理解表達的人。 如果論證是它更好地強調了這個函數返回TRUE或FALSE,那就意味着讀者不會知道func()是如何工作的,這些應該被那些看到函數的人理解並試圖真正理解邏輯而不僅僅是霰彈槍調試隨機的代碼位。

也就是說,這往往會在實踐中發生,因為多個開發人員維護代碼,因為人們暫時修改代碼以使調試更容易,等等。

我不認為這樣的代碼存在是一個問題,但我會斷言簡潔的解決方案更好,因為它保證它至少與更長的一個有效或更多,這意味着額外的開銷,我們只能希望讓編譯器優化掉(我不希望所有編譯器的這種分支情況都發生這種情況,即使現在優化編譯器有多好)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM