#c #if-statement #bit-manipulation #bitwise-operators
Вопрос:
Кто-нибудь, пожалуйста, объясните мне, как иметь одинаковую ценность VAL1
и VAL2
вести себя по-другому? Для первого if
утверждения VAL1
равно нулю? Спасибо!
#include <stdio.h>
#define VAL1 (1U << 1) | (1U << 5)
#define VAL2 0x22
int main()
{
printf("VAL1: %drn", VAL1);
printf("VAL2: %drn", VAL2);
if (VAL1 == 0)
{
printf("TRUE 1rn");
}
if (VAL2 == 0)
{
printf("TRUE 2rn");
}
if (VAL1 == VAL2)
{
printf("TRUE 3rn");
}
}
Выход:
VAL1: 34
VAL2: 34
TRUE 1
TRUE 3
Комментарии:
1. Приоритет оператора разума. Полностью заключите макросы в скобки.
2. Действительно, это работает. Такая маленькая деталь, но все же большая разница. Но почему именно так обстоит дело?
3.
#define VAL1 (1U << 1) | (1U << 5)
==> >#define VAL1 ((1U << 1) | (1U << 5))
Чтобы узнать, почему, запишите расширение.4. Существует два основных правила для написания правильных макросов выражений: (1) В теле макрокоманды заключите каждый аргумент (если таковой имеется) в круглые скобки и (2) Заключите все тело макрокоманды в круглые скобки. Невыполнение любого из этих действий может привести к нежелательной ассоциации в созданном макросе. Вы забыли (2), и в результате часть вашего макроса более тесно сгруппирована с оператором сравнения, что приводит к нежелательному поведению.
5. @Tom Karzes хотя ваши правила подходят для большинства выражений, они могут вызвать синтаксические ошибки со строковыми литералами. Рассмотрим #define PREF( a) «pref» a, который может использоваться для добавления «pref» к строковому литералу, как в PREF( «suf»), который расширяется до «pref» «suf», который компилятор преобразует в «prefsuf». Если вы примените одно из своих правил к PREF, вы получите синтаксическую ошибку при расширении. По общему признанию, ПРЕФ немного противный, но это макросы!
Ответ №1:
Оба числа одинаковы, но когда ваш макрос расширяется в ваших условиях, он ведет себя не так, как вы ожидаете, из-за приоритета оператора.
Другими словами, вот что вы получаете, когда расширяете:
(1U << 1) | (1U << 5) == 0
// is equivalent to
(1U << 1) | ((1U << 5) == 0)
Комментарии:
1. Решение:
#define VAL1 ( (1U << 1) | (1U << 5) )
Ответ №2:
В if (VAL1 == 0)
, замена макросов изменяет исходный код на if ((1U << 1) | (1U << 5) == 0)
.
Выражение внутри if
оценивается как (1U << 1) | ((1U << 5) == 0)
, из-за желания сохранить прецеденты операторов C в соответствии с прецедентами более раннего языка B.
Таким образом , мы имеем if ((1U << 1) | ((1U << 5) == 0))
, в котором (1U << 1)
значение равно 2 и ((1U << 5) == 0)
равно 0 , в результате if (2 | 0)
чего получается , что становится if (2)
, поэтому if
выполняется оператор с.
Принято определять замену макрокоманды, которая представляет собой выражение со скобками, чтобы гарантировать, что оно сгруппировано как один элемент:
#define VAL1 ((1U << 1) | (1U << 5))