Простите, если этот вопрос наивен. Рассмотрим следующую программу:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
В приведенном выше примере, операторы 5;
и i;
кажутся совершенно излишними, но код компилируется без предупреждений или ошибок по умолчанию (однако, НКУ делает бросить warning: statement with no effect [-Wunused-value]
предупреждение , когда бежал с -Wall
). Они не влияют на остальную часть программы, так почему же они в первую очередь считаются действительными утверждениями? Компилятор просто игнорирует их? Есть ли какие-либо преимущества в разрешении таких заявлений?
;
после него. Это усложнит язык, добавив больше правил, когда выражения не могут быть утверждениямиprintf()
? В заявлении в5;
основном говорит , «делать все , что5
не делает (ничего) , и игнорировать результат. Ваше заявлениеprintf(...)
является„делать все , чтоprintf(...)
делает , и игнорировать результаты (возвращаемое значениеprintf()
)“. C лечит те же самое. Это также позволяет кода , такие как ,(void) i;
гдеi
находится параметр функции, которую вы приводите, чтобыvoid
пометить его как намеренно неиспользуемыйprintf()
имеет эффект, даже если вы игнорируете значение, которое он в конечном итоге возвращает. В отличие от5;
этого не имеет никакого эффекта вообще.Ответы:
Одно из преимуществ использования таких утверждений - это код, который создается макросами или другими программами, а не написан людьми.
В качестве примера представим функцию,
int do_stuff(void)
которая должна возвращать 0 в случае успеха или -1 в случае неудачи. Может случиться так, что поддержка «вещи» не является обязательной, и поэтому вы можете иметь заголовочный файл, который делаетТеперь представьте некоторый код, который хочет что-то делать, если это возможно, но может не заботиться о том, будет ли он успешным или неудачным:
Когда
STUFF_SUPPORTED
0, препроцессор расширит вызовfunc2
до оператора, который просто читаети поэтому проход компилятора увидит только то «лишнее» утверждение, которое вас беспокоит. Но что еще можно сделать? Если вы
#define do_stuff() // nothing
, то код вfunc1
сломается. (И у вас все еще будет пустой оператор,func2
который просто читает;
, что, возможно, еще более излишне.) С другой стороны, если вам действительно нужно определитьdo_stuff()
функцию, которая возвращает -1, вы можете понести стоимость вызова функции без веской причины.источник
((void)0)
.assert
.Простые операторы в C заканчиваются точкой с запятой.
Простые утверждения в C являются выражениями. Выражение представляет собой комбинацию переменных, констант и операторов. Каждое выражение приводит к некоторому значению определенного типа, которое может быть присвоено переменной.
Сказав, что некоторые «умные компиляторы» могут отказаться от 5; и я; заявления.
источник
void
не имеет значения.Заявления без последствий разрешены, потому что было бы сложнее их запретить, чем разрешить. Это было более актуально, когда C был впервые разработан, а компиляторы были меньше и проще.
Выражение оператор состоит из выражения , за которым следует точка с запятой. Его поведение заключается в оценке выражения и отбрасывании результата (если есть). Обычно цель состоит в том, чтобы оценка выражения имела побочные эффекты, но не всегда легко или даже невозможно определить, имеет ли данное выражение побочные эффекты.
Например, вызов функции - это выражение, поэтому вызов функции, за которым следует точка с запятой, - это оператор. Есть ли у этого утверждения какие-либо побочные эффекты?
Невозможно сказать, не видя реализации
some_function
.Как насчет этого?
Вероятно, нет - но если
obj
определяется какvolatile
, то это так.Разрешение превращения любого выражения в выражение-выражение путем добавления точки с запятой упрощает определение языка. Требование к выражению иметь побочные эффекты усложнит определение языка и компилятор. C построен на непротиворечивом наборе правил (вызовы функций - это выражения, присваивания - это выражения, выражение, за которым следует точка с запятой - это оператор), и позволяет программистам делать то, что они хотят, не мешая им делать то, что может иметь или не иметь смысла.
источник
Выражения , которые вы перечислили без эффекта, являются примерами выражения выражения , синтаксис которого приведен в разделе 6.8.3p1 стандарта C следующим образом:
Весь раздел 6.5 посвящен определению выражения, но условно говоря, выражение состоит из констант и идентификаторов, связанных с операторами. Примечательно, что выражение может содержать или не содержать оператор присваивания и может содержать или не содержать вызов функции.
Таким образом, любое выражение, за которым следует точка с запятой, квалифицируется как выражение выражения. Фактически, каждая из этих строк в вашем коде является примером выражения выражения:
Некоторые операторы содержат побочные эффекты, такие как набор операторов присваивания и операторы до / после увеличения / уменьшения, а оператор вызова функции
()
может иметь побочный эффект в зависимости от того, что делает рассматриваемая функция. Однако не требуется, чтобы один из операторов имел побочный эффект.Вот еще один пример:
Это вызывает функцию и отбрасывает результат, точно так же как вызов
printf
в вашем примере, но в отличие отprintf
самого вызова функции не имеет побочного эффекта.источник
Иногда такие заявления очень удобны:
Или когда справочное руководство говорит нам просто читать регистры для архивирования чего-либо - например, для очистки или установки какого-либо флага (очень распространенная ситуация в мире ОК)
https://godbolt.org/z/6wjh_5
источник
*SREG
летуч,*SREG;
не не имеет никакого эффекта в модели , указанной в стандарте C. Стандарт C указывает, что он имеет наблюдаемый побочный эффект.