Зачем кому-то это использовать?
if(a==1){;}
Нет инструкции, только одна точка с запятой, и она не выдает ошибку. Какую цель выполняет эта точка с запятой?
Зачем кому-то это использовать?
if(a==1){;}
Нет инструкции, только одна точка с запятой, и она не выдает ошибку. Какую цель выполняет эта точка с запятой?
Это пустое утверждение. Одна точка с запятой сама по себе не выполняет никаких операций.
В этом контексте это означает, что если условие if
истинно, ничего не делать.
Без раздела else
в этом коде не так много пользы. Если есть, то вопрос о том, должно ли условие быть инвертировано и должно содержать только непустую часть if
.
В этом случае это простой условный, поэтому по стилю он, вероятно, лучше инвертировать его, однако, если условие более сложное, может быть яснее написать этот путь. Например, это:
if ((a==1) && (b==2) && (c==3) && (d==4)) {
;
} else {
// do something useful
}
Может быть яснее, чем это:
if (!((a==1) && (b==2) && (c==3) && (d==4))) {
// do something useful
}
Или это:
if ((a!=1) || (b!=2) || (c!=3) || (d!=4)) {
// do something useful
}
Лучший пример из комментариев (спасибо Бен):
if (not_found) {
;
} else {
// do something
}
Versus:
if (!not_found) {
// do something
}
Какой метод использовать во многом зависит от того, что именно сравнивается, сколько терминов есть, как вложены термины и даже имена переменных/функций.
Другим примером того, когда вы можете использовать это, является то, что у вас есть набор операторов if..else
для проверки диапазона значений и вы хотите документировать в коде, что ничего не должно происходить для определенного диапазона:
if (a < 0) {
process_negative(a);
} else if (a >=0 && a < 10) {
process_under_10(a);
} else if (a >=10 && a < 20) {
; // do nothing
} else if (a >=20 && a < 30) {
process_20s(a);
} else if (a >= 30) {
process_30s_and_up(a);
}
Если пустой if
был опущен, читатель мог бы задаться вопросом, должно ли что-то произошло там, и разработчик забыл об этом. Включая пустой if
, он говорит читателю: "Да, я объяснил это, и в этом случае ничего не должно произойти".
Некоторые стандарты кодирования требуют, чтобы все возможные результаты были явно учтены в коде. Таким образом, код, придерживающийся такого стандарта, может выглядеть примерно так.
Он вызвал нулевой оператор.
Из 6.8.3 Выражения и нулевые утверждения:
Оператор null (состоящий только из точки с запятой) не выполняет никаких операции.
В этом конкретном примере if(a==1){;}
он не делает ничего полезного (кроме, возможно, более очевидного), так же как if(a==1){}
или if(a==1);
.
Никакой цели вообще. Это пустое утверждение. Возможно, разработчик хотел что-то сделать, если a
не был 1
, и в этом случае код был бы чем-то вроде (даже если ;
можно опустить):
if(a==1)
{
;
}
else
{
//useful code...
}
Но в этом случае его можно было бы легко записать как if(a != 1)
.
Обратите внимание, что если это С++ (теги еще не ясны), тогда существует вероятность перегрузки operator==
типа a
, и некоторые побочные эффекты могут быть обнаружены. Это означало бы, что код безумный, хотя.
Это так называемый оператор null. Это своего рода выражение, в котором выражение отсутствует.
Иногда он используется в операторах if-else, как вы показали, когда легко записать условие if, чем его отрицание (или условие if более понятно), но код должен выполняться, когда условие if оценивается как false.
Например
if ( some_condition )
{
; // do nothing
}
else
{
// here there is some code
}
Обычно оператор null используется для изложения только для того, чтобы показать, что, например, тело функции или конструктор класса или цикл for пуст. Например
struct A
{
A( int x ) : x( x )
{
;
}
//...
};
или
char * copy_string( char *dsn, const char *src )
{
char *p = dsn;
while ( ( *dsn++ = *src++ ) ) ;
^^^
return p;
}
Здесь нулевой оператор требуется для цикла while. Вы также можете переписать его как
while ( ( *dsn++ = *src++ ) ) {}
Иногда нулевой оператор требуется особенно в редких случаях, когда используется инструкция goto. Например, в объявлениях C нет утверждений. Если вы хотите передать управление программой в точку перед некоторым объявлением, вы можете поместить ярлык перед объявлением. Однако в C метка может быть помещена только перед оператором. В этом случае вы можете поместить нулевой оператор с меткой перед объявлением. Например
Repeat:;
^^^
int a[n];
//....
n++;
goto Repeat;
Обратите внимание на нулевую инструкцию после метки. Если его удалить, то компилятор C выдаст ошибку.
Этот трюк также используется для передачи управления программой в конец составного оператора. Например
{
// some code
goto Done;
//...
Done:;
}
Хотя вы не должны использовать инструкцию goto, но вы должны знать об этих случаях.:)
Как говорили многие, он ничего не делает.
Почему он там? Вот возможность...
Я устал от плохих кодеров в моей команде, не проверяя возвращаемые значения функций.
Итак, поскольку мы разрабатываем в Linux с компилятором GCC, я добавляю __attribute__((warn_unused_result))
к объявлению всех моих типизированных функций. См. Также этот вопрос для эквивалента MS VC.
Если пользователь не проверяет возвращаемое значение, компилятор генерирует предупреждение.
Ковбои, конечно же, играли в систему и код if (foo() != SUCCESS) ;
, который удовлетворяет компилятору (хотя он не удовлетворяет мне: -).
Единственный ;
- это нулевой оператор, который ничего не делает. Он часто используется в длинных цепочках if/else, например:
if (a == 1) {
// Do nothing.
;
}
else if (...) {
...
}
else if (...) {
...
}
Это также можно записать как:
if (a != 1) {
if (...) {
...
}
else if (...) {
...
}
}
Последний добавляет еще один уровень отступов, но IMO, это яснее. Но null-инструкции иногда могут быть полезны, чтобы избежать чрезмерного отступа, если существует несколько ветвей без кода.
Обратите внимание, что пустой составной оператор (также называемый блоком) имеет тот же эффект:
if (a == 1) {}
Технически вам нужна точка с запятой, если вы хотите напрямую использовать оператор выражения:
if (a == 1) ;
else if (...) { ... }
else if (...) { ... }
Таким образом, запись {;}
является избыточной и служит лишь для сомнительной иллюстративной цели.
Другой пример из стандарта C, где оператор null используется для подачи пустого тела цикла:
char *s;
/* ... */
while (*s++ != '\0')
;
Но здесь я также предпочел бы пустое составное утверждение.
Это в основном оператор null/empty, который делает ничего и, как и ожидалось, доброкачественный (без ошибок) характер.
C Проект черновика N1570 поясняет, что:
- выражения необязательны: выражение [opt];
- Оператор null (состоящий только из точки с запятой) не выполняет никаких операций.
С другой стороны, Bjarne цитирует в своей книге на С++ #9.2 Statement Summary
:
Точка с запятой - это оператор, пустой оператор.
Обратите внимание, что эти два кода if(1) {;}
и if(1) {}
имеют нет разницы в сгенерированных инструкциях gcc.
;
сам по себе является пустой инструкцией. Если a
является инициализированным не указательным типом, то
if(a==1){;}
всегда является no-op в C. Использование фигурных скобок добавляет дополнительный вес к утверждению о том, что нет опечатки. Возможно, под ним находится else
, который будет выполняться, если a
не был 1.
Зачем вам это делать? Я все время делаю подобные вещи, когда отлаживаю, чтобы дать мне что-то, что (надеюсь) не будет оптимизировано, поэтому я могу поставить точку останова на нем.
Обычно, хотя я делаю это очевидным, отметка отладки
if( (a==1) && (b==2) && (c==3) && (d==4) ){
int debug=1;
}
В противном случае я получаю странные маленькие кусочки кода, застрявшие повсюду, которые не имеют абсолютно никакого смысла даже для меня.
Но это не гарантирует, что это было.
; это пустой оператор noop
В чем его цель?
Иногда мы просто хотим сравнить вещи, как в этом случае, равенство a и 1. С примитивными типами, такими как integer, это установит регистр условий, если вы после этого, если что-то вроде if (a > 1) или if ( a < 1) и a не изменяется в то же время, это может не быть оценено снова в зависимости от решения компилятора.
Этот код
int f(int a){
if(a == 1){;}
if(a > 1){return 3;}
if(a < 1){return 5;}
return 0;
}
даст
.file "c_rcrYxj"
.text
.p2align 2,,3
.globl f
.type f, @function
f:
.LFB0:
.cfi_startproc
cmpl $1, 4(%esp)
jle .L6
movl $3, %eax
ret
.p2align 2,,3
.L6:
setne %al
movzbl %al, %eax
leal (%eax,%eax,4), %eax
ret
.cfi_endproc
.LFE0:
.size f, .-f
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
Сравнение выполняется только один раз cmpl $1, 4 (% esp), где именно (a == 1) записано.
Вероятно, вы уже знаете, что точка с запятой - это пустой оператор. Что касается фактического вопроса: "Какая цель служит этой точкой с запятой", то ответ будет (если автор этого кода не захотел оживить код каким-то странным смайликом), что он служит абсолютно цели вообще. То есть {;}
полностью эквивалентен {}
в любом контексте (где ожидается утверждение, которое, я думаю, является единственным местом, где {;}
можно использовать). Присутствие точки с запятой изменяет составной оператор с 0 составными операторами в составной оператор с одним составным выражением, который является пустым оператором, но оба случая эквивалентны по отношению к семантике.
Я добавлю личное мнение о том, что для удобства чтения, не будучи случайно упущенным читателем кода, {;}
не лучше {}
(если это было, то, возможно, {;;;;;;;;}
было бы лучше), хотя оба они значительно лучше, чем одиночные ;
(и, как следствие, язык был бы лучше, не позволяя ;
как пустой оператор вообще, так как замена его на {}
всегда выгодна).