Почему (пусто) 0 не операция в C и C++?

Я видел отладку printfs в glibc, который внутренне определяется как (void) 0, если NDEBUG определяется. Аналогично __noop для Visual C++ компилятор там также. Бывшие работы и над GCC и над VC ++ компиляторы, в то время как последний только на VC ++. Теперь все мы знаем, что и вышеупомянутые операторы не будут рассматривать как никакую операцию и никакой соответствующий код, будет сгенерирован; но вот то, где у меня есть сомнение.

В случае __noop, MSDN заявляет, что это - встроенная функция, обеспеченная компилятором. Прибытие в (void) 0 ~, Почему это интерпретируется компиляторами как никакой op? Действительно ли это - хитрое использование языка C, или в стандарте говорится что-то об этом explicity? Или даже который относится к чему-то реализация компилятора?

48
задан legends2k 4 February 2010 в 11:16
поделиться

3 ответа

(void)0 (+;)) является допустимым, но выражение 'does-nothing' C++, вот и все. Оно не переводится в инструкцию no-op целевой архитектуры, это просто пустой оператор в качестве плацдарма, когда язык ожидает полного оператора (например, в качестве мишени для метки скачка, или в теле выражения if).

EDIT: (обновлено на основе комментария Криса Лутца)

Следует отметить, что при использовании в качестве макроса, скажем

#define noop ((void)0)

, (void) предотвращает его случайное использование в качестве значения типа

int x = noop;

Для приведенного выше выражения компилятор справедливо пометит его как недействительную операцию. GCC выплескивает ошибка: значение void не игнорируется как должно быть и VC++ barks 'void' illegal со всеми типами.

66
ответ дан 26 November 2019 в 18:53
поделиться

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

9
ответ дан 26 November 2019 в 18:53
поделиться

Думаю, вы говорите о glibc , а не о glib , и рассматриваемый макрос - это макрос assert :

В файле glibc , с определенным NDEBUG (без отладки), assert определяется как:

#ifdef NDEBUG
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
# define assert(expr)           (__ASSERT_VOID_CAST (0))
#else
/* more code */
#endif

что в основном означает assert (что угодно); эквивалентно ((void) (0)); и ничего не делает.

Из стандарта C89 (раздел 4.2):

Заголовок определяет макрос assert и ссылается на другой макрос,

 NDEBUG {{ 1}} 

, который не определен в . Если NDEBUG определен как имя макроса в той точке исходного файла, где включен , макрос assert определяется просто как

 #define assert (ignore) ((void) 0) 
 

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

3
ответ дан 26 November 2019 в 18:53
поделиться