Яка мета блоку "if (0)" у блоці if-else?


141

Моє запитання стосується рядка, який я згадав у цій темі, і який я бачу в багатьох місцях всередині виробничого коду.

Загальний код виглядає приблизно так:

if (0) {
    // Empty braces
} else if (some_fn_call()) {
    // actual code
} else if (some_other_fn_call()) {
    // another actual code
    ...
} else {
    // default case
}

Інші галузі не стосуються мого питання. Мені цікаво, в чому сенс ставити if (0)сюди. Дужки порожні, тому я не думаю, що він повинен коментувати якийсь блок коду. Чи змушує компілятор зробити деяку оптимізацію чи її наміри відрізняються?

Я намагався шукати цей явний випадок і тут, і в Інтернеті, але не маючи успіху. Існують подібні запитання щодо JavaScript, але не C. Є ще одне запитання: що відбувається, коли нуль присвоєно в умові "якщо"? , але він обговорює нульове призначення змінній, а не використання 'if (0)'.


2
Це твердження видається несуттєвим. Створіть код складання з і без цього твердження, і ви побачите, що відбувається під капотом.
хакі

2
Можливо, це автоматично генерований код.
фрік

Відповіді:


91

Я іноді використовую це для симетрії, щоб я міг else if{вільно переміщати іншого за допомогою свого редактора, не маючи на увазі першого if.

Семантично

if (0) {
    // Empty braces
} else 

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


239
Особиста думка: Хоча це може бути причиною коду, чому він написаний таким, яким він є, я вважаю, що це неправильне виправдання. Код читається частіше, ніж написано, і цей непотрібний код просто збільшує розбір витрат для читача.
користувач694733

13
@ user694733: Ви можете стверджувати, що загальний if elseпрефікс для всіх значущих кодових шляхів добре узгоджує умови та полегшує їх сканування. (Це, однак, суб'єктивно, і багато чого залежатиме від того, що насправді знаходиться в умовах та блоках коду.)
M Oehm

72
Я не думаю, що if (0) {..}вводиться будь-яка проблема зі зручністю чи читанністю. Це повинно бути очевидним для кожного, хто знає трохи C. Це не проблема. Проблема полягає в наступному питанні після його прочитання: "Що за то чорт?" Якщо це не для налагодження / тимчасових цілей (тобто намір полягає в тому, щоб "включити" цей ifблок пізніше), я б рекомендував видалити його взагалі. В основному, "читання" такого коду, ймовірно, спричинить непотрібну "паузу" для читача без поважних причин. І це досить вагомий привід, щоб його зняти.
ПП

77
Здається, це безумовно шкодить читабельності. Це було так погано, що він послав цього програміста до SO, щоб запитати, що це таке. Не гарний знак.
Vectorjohn

26
Навіть використовуючи цю схему, я не знаю, чи можна без проблем пересуватися else ifпо редактору, оскільки умови можуть не бути взаємовиключними, і в цьому випадку порядок має значення. Особисто я би використовував тільки ifта виконував раннє повернення , витягуючи логічний ланцюг в окрему функцію, якщо це необхідно.
Джон Ву

105

Це може бути корисно, якщо є #ifтвердження, аля

   if (0)
   {
       // Empty block
   }
#if TEST1_ENABLED
   else if (test1())
   {
      action1();
   }
#endif
#if TEST2_ENABLED
   else if (test2())
   {
      action2();
   }
#endif

тощо.

У цьому випадку будь-який (і всі) тести можуть бути #ifвидалені, і код буде складено правильно. Практично всі компілятори видалять if (0) {}частину. Простий автогенератор може генерувати подібний код, оскільки його трохи простіше кодувати - він не повинен розглядати перший включений блок окремо.


5
У багатьох випадках an if/ else ifланцюг використовується не стільки, як дерево рішення, а як конструкція "дія при першій відповідності умові", де умова, яка має найвищий пріоритет, не є особливо "особливою". Хоча я не бачив, if(0)як використовується як спосіб дозволити всім реальним гілкам мати послідовний синтаксис, мені подобається послідовний синтаксис, який він полегшує.
supercat

1
Це навіть не корисно в цьому випадку, оскільки ви можете домогтися такого ж ефекту і без цього: просто розділіть else ifрядок на два і покладіть між собою захист препроцесора.
Конрад Рудольф

1
@KonradRudolph Я не слідкую; як би ти це написав?
JiK

1
@JiK Я би видалив if (0)гілку та переформатував решту таких, що elseзнаходяться на власній лінії, оточений сторожею по лінії #if TEST1_ENABLED && TEST2_ENABLED.
Конрад Рудольф

5
@KonradRudolph це добре, якщо ви хочете подвоїти кількість охоронців і потроїти кількість згаданих умов охорони, я думаю.
варення

44

Я бачив подібну схему, що використовується в створеному коді. Наприклад, у SQL я бачив, як бібліотеки випромінюють таке whereположення.

where 1 = 1

Це, мабуть, полегшує додавання інших критеріїв, тому що всі додаткові критерії можуть бути попередньо andзамість додаткової перевірки, щоб побачити, чи це перший критерій чи ні.


4
Це 1=1також "корисно", оскільки ви завжди можете додавати whereфронт, безумовно. В іншому випадку вам доведеться перевірити, чи порожній він, і якщо так, уникайте створення whereпункту.
Бакуріу

2
Крім того, більшість баз даних автоматично "видалять" дані 1=1з WHERE, тому це не впливає на продуктивність.
Позов про Моніку

7
Це прийнятно в бібліотеці, яка автоматично генерує запити SQL, які, швидше за все, ніколи не бачать навіть команда DevOps. Код високого рівня не є "прийнятним", який потрібно писати і читати кілька разів.
Фагіо

Це дійсно зручний підхід при генерації якогось динамічного SQL з невідомою кількістю кінцевих умов.
Шкіпер

1
@freakish дійсно я написав протилежне: погано читабельний синтаксис є прийнятним у створеному коді, оскільки він, швидше за все, ніколи не буде прочитаний, не у функціональному коді високого рівня, який підтримується розробниками.
фагіо

44

Як написано, if (0) {} стаття складається ні до чого.

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


2
Прибив його. Окрім налагодження я не побачив жодної іншої причини.
tfont

16

Я не впевнений у будь-яких оптимізаціях, але два мої центи:

Це сталося через деяку модифікацію коду, де було видалено одну первинну умову (виклик функції у початковому ifблоці, скажімо), але розробники / підтримуючі

тож замість видалення асоційованого ifблоку вони просто змінили умову на if(0)та перейшли.


3
Чи не if(0)зменшується також охоплення філій?
Девід Шалай

1
@DavidSzalai Не повністю - максимум, вона зменшиться на 1 (з попередніх 2) - але все одно, для моїх знань, все одно знадобиться для висвітлення.
Sourav Ghosh

15

Це кодова гниль.

У якийсь момент, що "якщо" зробив щось корисне, ситуація змінилася, можливо, змінна, що оцінюється, була видалена.

Людина, яка виправляла / змінювала систему якомога менше впливати на логіку системи тому він просто переконався, що код буде перекомпільований. Тож він залишає "if (0)", тому що це швидко і просто, і він не зовсім впевнений, що це хоче зробити. Він змушує роботу системи, і він не повертається, щоб виправити її повністю.

Потім приходить наступний розробник і думає, що це було зроблено навмисно, і лише коментує ту частину коду (оскільки вона так чи інакше не оцінюється), то наступного разу, коли код торкнеться цих коментарів, видаляються.


2
Так. Для стародавнього коду внесіть одночасно зміни, що видаляють мертвий код. Я не можу підрахувати, скільки разів я потрапляв на сказу "косого і спалення" проти "мертвого" коду, лише щоб виявити, що є якийсь химерний побічний ефект, який прорізав і спалював.
Джулі в Остіні

15

Ще не вказана одна можливість: if (0) {лінія могла б забезпечити зручне місце для точки перелому.

Налагодження часто проводиться на неоптимізованому коді, тому тест, який завжди є помилковим, буде присутній і зможе встановити на ньому точку перерви. Коли буде складено для виробництва, рядок коду буде оптимізовано. Начебто марна лінія надає функціональність для розробки та тестування збірок, не впливаючи на версії версій.

Вище є й інші хороші пропозиції; єдиний спосіб дійсно знати, яка мета, - це вистежити автора і запитати. Ваша система управління вихідним кодом може допомогти у цьому. (Шукайте blameфункціональність типу).


9

Я бачив блоки недоступних кодів у попередньо розширеному JavaScript, які були створені за допомогою мови шаблонів.

Наприклад, код, який ви читаєте, міг бути вставлений із сервера, який попередньо оцінив першу умову, яка на той час спиралася на змінну, доступну лише на стороні сервера.

if ( ${requestIsNotHttps} ){ ... }else if( ...

який колись попередньо склав:

if ( 0 ){ ... }else if ( ...

сподіваємось, це допоможе вам відновити потенційну низьку активність клавіатури епохи кодек, що переробляються, за що я проявляю захоплення!


1
Я згоден, в епоху всюдисущої автоматизації нам слід більше покладатися на автогенерований код, оскільки він дозволяє нам витрачати більше часу на фактичні речі. Але наразі моя точна цікава точка - як це все архітектурно під капотом.
Zzaponka

8

Ця конструкція також може бути використана в C для реалізації загального програмування з безпекою типу, спираючись на той факт, що недоступний код все ще перевіряється компілятором:

// this is a generic unsafe function, that will call fun(arg) at a later time
void defer(void *fun, void *arg);

// this is a macro that makes it safer, by checking the argument
// matches the function signature
#define DEFER(f, arg) \
   if(0) f(arg); \              // never actually called, but compile-time checked
   else defer(f, (void *)arg);  // do the unsafe call after safety check

void myfunction(int *p);

DEFER(myfunction, 42);     // compile error
int *b;
DEFER(myfunction, b);      // compiles OK

6

Я думаю, що це просто поганий код. Написавши короткий приклад у Провідника компілятора, ми бачимо, що і в gcc, і в clang не створюється код дляif (0) блоку, навіть при повністю відключених оптимізаціях:

https://godbolt.org/z/PETIks

Займаючись видаленням if (0)причин, зміни у створеному коді не змінюються, тому я роблю висновок, що це не оптимізація.

Можливо, що у верхньому ifблоці було щось, яке згодом було видалено. Коротше кажучи, схоже, що його видалення призведе до генерування точно такого ж коду, тому сміливо робіть це.


6

Як було сказано, нуль оцінюється як хибний, і гілка, ймовірно, буде оптимізована компілятором.

Я також бачив це раніше в коді, коли була додана нова функція і потрібен перемикач kill (якщо щось піде не так з функцією, ви можете просто вимкнути її), і через деякий час, коли перемикач kill був видалений програміст також не видалив гілку, наприклад

if (feature_a_active()) {
    use_feature_a();
} else if (some_fn()) {
   ...

став

if (0) {
   // empty
} else if (some_fn()) {
   ...

1

Це допомагає налагодити цей блок, просто встановивши, якщо блок 1. Це вимкнення всіх, якщо ще функціональність блоку. А також ми можемо розширити блок if if.


1
    Actually according to my opinion, if we put any variable for checking inside
    e.g:-
public static void main(string args[])
{
        var status;
        var empList=_unitofWork.EmpRepository.Get(con=>con.isRetired==true);
        //some code logic 
        if(empList.count>0)
        {
          status=true;
        }
        if(status)
        {
         //do something
        }
        else
        {
        //do something else
        }
}
     if then its dynamically get the value in run time and invoke the logic inside it, else its simply extra line of code i guess.

    Anybody have any depth knowledge why this thing is used....or agree with me.
    kindly respond. 

1

@ Відповідь PSkocik чудова, але я додаю свої два центи. Не впевнений, чи потрібно це робити як коментар чи як відповідь; вибір останнього, оскільки ІМХО варто бачити інших, тоді як коментарі часто непомітні.

Мало того, що я час від часу використовую

if(0) {
   //deliberately left empty
} else if( cond1 ) {
   //deliberately left empty
} else if( cond2 ) {
   //deliberately left empty
...
} else {
   // no conditions matched
}

Але я теж час від часу роблю

if( 1 
    && cond1 
    && cond2
    ...
    && condN
) {

або

if( 0 
    || cond1 
    || cond2
    ...
    || condN
) {

для складних умов. З тих же причин - простіше редагувати, #ifdef тощо.

З цього приводу в Перлі я зроблю

@array = (  
    elem1,
    elem2,
    ...
    elem1,
) {
  • відзначте кому в кінці списку. Я забуваю, якщо коми є роздільниками або роздільниками у списках C і C ++. ІМХО, це одне, чого ми дізналися: [ Чи є трелі комами в Перлі поганою практикою? коми] - добра справа. Як і будь-яке нове позначення, потрібно звикати час.

Я порівнюю if(0)код з lisp

(cond   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn))

який, ви здогадалися, я можу відступити як

(cond   
   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn)
)

Я іноді намагався уявити, як може виглядати більш читаний для людини синтаксис.

Можливо,

IF
:: cond1 THEN code1
:: cond2 THEN code2
...
:: condN THEN codeN
FI

натхненний програмою [ https://en.wikipedia.org/wiki/Guarded_Command_Language#Selection:_if обвиненийGuarded Command Language].

Але цей синтаксис означає, що умови оцінюються паралельно, тоді як if...else-ifпередбачає послідовну та пріоритетну оцінку умов.

Я почав займатися подібною справою, коли писав програми, які створювали інші програми, де це особливо зручно.

Поки ми перебуваємо на цьому, під час написання RTL за допомогою старого iHDL від Intel я кодував такі речі

   IF 0 THEN /*nothing*/
   **FORC i FROM 1 TO 10 DOC** 
   ELSE IF signal%i% THEN    
      // stuff to do if signal%i% is active
   **ENDC** 
   ELSE   
      // nothing matched 
   ENDIF

де FORC..DOC..ENDCє конструкція циклу макропропроцесора, яка розширюється на

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      // stuff to do if signal1 is active
   ELSE IF signal2 THEN    
      // stuff to do if signal2 is active
   ...
   ELSE IF signal100 THEN    
      // stuff to do if signal100 is active
   ELSE   
      // nothing matched 
   ENDIF

Це був єдиний присвоєння, необов'язковий код, тому встановлення змінної стану заборонено, якщо вам потрібно було робити такі речі, як знайти перший встановлений біт.

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      found := 1
   ELSE IF signal2 THEN    
      found := 2
   ...
   ELSE IF signal100 THEN    
      found := 100
   ELSE   
      // nothing matched 
   ENDIF

Подумайте, це, можливо, було першим місцем, коли я стикався з такими конструкціями.

BTW, заперечення, що деякі мали у стилі if (0) - що умови "else-if" є послідовно залежними і не можуть бути довільно упорядковані - не застосовуються до логіки AND та OR або XOR в RTL - але стосуються коротких- ланцюг && та ||


-1

Я бачив, як це використовується для обробки помилок, наприклад

if(0){
lable1:
   //do something
}
if(0){
lable2:
   //do something
}
.
.
and so on.

if(condition_fails)
   goto lable1;

Це може бути корисно, коли goto використовується для управління помилками, оператори виконуються лише тоді, коли виникає помилка. Я бачив це в дуже старому C-коді (де аргументи функції записуються поза '()'), не думаю, що зараз це слідкує.


-2

Я бачив це кілька разів, я вважаю, що найвірогіднішою причиною є те, що це було оцінювати щось у старій / іншій версії / гілці коду, або можливо для налагодження, і змінити його на if(0)дещо ледачий спосіб видалити все, що там було .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.