Есть ли преимущество такого стиля кодирования? - PullRequest
5 голосов
/ 05 декабря 2011

| В плагине 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 ]

7 голосов
/ 05 декабря 2011

Это часть шаблона.

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

return true;

Кто бы ни написал, он решил не менять шаблон только потому, что есть только один вызов функции. В конечном счете, это вопрос вкуса.

4 голосов
/ 05 декабря 2011

Как таковой, нет проблем с кодом. По крайней мере, я не буду наказывать, если кто-либо использует любой из упомянутых фрагментов.

Вот причины, которые я считаю причиной:

  • Прежде всего это удобочитаемость. Теперь, глядя на код раздела, я знаю, что является успехом, а что нет. Как может быть apis, который ведет себя обратно (даже в C).
  • Вторая причина возникает, когда во время тестирования вы хотите распечатать некоторые записи журнала. Теперь, если вы вернетесь напрямую, вы не сможете записать возвращаемое значение или любую отладочную информацию. Вы можете сказать, что после освобождения кода его следует удалить, но для следующего выпуска вам, возможно, придется снова добавить операторы отладки. Так и остается там.
  • Третья причина может заключаться в том, что некоторый код удаляется во время разработки.

Заключение - это то, что я сказал в начале. Это не имеет значения, поскольку код легко понять. Что касается некоторых преимуществ оптимизации, я думаю, что компиляторы достаточно умны, чтобы позаботиться.

3 голосов
/ 05 декабря 2011

По сути, нет: он использует больше кода и больше инструкций, чтобы сказать то же самое.

Обычно это указывает на одну из двух вещей:

  • кого-то, кто не оченьудобен код C
  • , где кто-то планировал сделать что-то большее с отрицательным возвратом, например, записать сообщение об ошибке, но не сделал этого.

Хм.В данном случае это может указывать код переведенный механически, скажем, Fortran.

1012 * Обновлены снова 1016 * Хорошо, так что это еще спорный.Вот реальный пример.Обратите внимание, что пример точно изоморфен примеру 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

Опять же, все еще значительнокороче.

Наконец, вот пример, на этот раз с full оптимизацией:

.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:                             

Теперь обратите внимание, что даже при полной оптимизации он все еще не создает точно того же кода, который был заявлен.

1 голос
/ 28 февраля 2012

Я бы вышел на конечности и просто сказал бы прямо, что да, последний стиль лучше. То есть:

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

... и предполагая, что func () уже возвращает логическое значение, приведенный выше стиль уступает:

return func();

Если первое кажется более читабельным, я бы умолял тех, кто так думает, чтобы лучше понять выражения. Если аргумент состоит в том, что лучше подчеркнуть, что эта функция возвращает TRUE или FALSE, это означает, что читатель не будет знать, как работает func(), что должно быть понято теми, кто смотрит на функцию и пытается действительно понять логику, а не просто дробовик отладка случайных битов кода.

Тем не менее, это имеет место на практике, так как несколько разработчиков поддерживают код, когда люди временно изменяют код для облегчения отладки и т. Д.

Я бы не считал наличие такого кода проблемой, но я бы утверждал, что краткое решение лучше, поскольку оно гарантирует, что оно, по крайней мере, столь же эффективно или больше, чем более длинное, что подразумевает дополнительные накладные расходы, которые мы можно только надеяться на то, что компилятор будет оптимизирован (и я бы не ожидал, что это произойдет с подобными случаями ветвления для всех компиляторов, даже несмотря на то, насколько хороши оптимизирующие компиляторы в настоящее время).

1 голос
/ 05 декабря 2011

В дополнение к тому, что уже было сказано, и поскольку это помеченный стиль кодирования, первый код содержит некоторый стиль, который можно считать опасным.Но так как это стиль кодирования, мнения о нем будут субъективными.

  • Многочисленные операторы возврата считаются плохим и опасным стилем для многих программистов.
  • if без следующих скобок многими программистами считается плохим и опасным стилем.То же самое для else, else if, for, while, do...while, switch.

Оба эти стиля запрещены, например, MISRA-C (MISRA-C: 2004 14.7 и 14.8).

(Лично я надеваюне согласен с первым из этих двух, я думаю, что во многих случаях множественные операторы возврата делают код более читабельным, особенно в функциях, где выполняется много ошибок, таких как парсеры и т. д.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...