Я видел отладку printfs в glibc, который внутренне определяется как (void) 0
, если NDEBUG определяется. Аналогично __noop
для Visual C++ компилятор там также. Бывшие работы и над GCC и над VC ++ компиляторы, в то время как последний только на VC ++. Теперь все мы знаем, что и вышеупомянутые операторы не будут рассматривать как никакую операцию и никакой соответствующий код, будет сгенерирован; но вот то, где у меня есть сомнение.
В случае __noop
, MSDN заявляет, что это - встроенная функция, обеспеченная компилятором. Прибытие в (void) 0
~, Почему это интерпретируется компиляторами как никакой op? Действительно ли это - хитрое использование языка C, или в стандарте говорится что-то об этом explicity? Или даже который относится к чему-то реализация компилятора?
(void)0
(+;
)) является допустимым, но выражение 'does-nothing' C++, вот и все. Оно не переводится в инструкцию no-op
целевой архитектуры, это просто пустой оператор в качестве плацдарма, когда язык ожидает полного оператора (например, в качестве мишени для метки скачка, или в теле выражения if
).
EDIT: (обновлено на основе комментария Криса Лутца)
Следует отметить, что при использовании в качестве макроса, скажем
#define noop ((void)0)
, (void)
предотвращает его случайное использование в качестве значения типа
int x = noop;
Для приведенного выше выражения компилятор справедливо пометит его как недействительную операцию. GCC выплескивает ошибка: значение void не игнорируется как должно быть
и VC++ barks 'void' illegal со всеми типами
.
Любое выражение, не имеющее побочных эффектов, может быть расценено компилятором как no-op, который не должен генерировать для него никакого кода (хотя может и генерировать). Так получилось, что кастинг, а затем и не использование результата кастинга легко воспринимается компилятором (и людьми) как не имеющее побочных эффектов.
Думаю, вы говорите о 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
имеет большой смысл. Вы можете показать нам, где это делается?