这个密码是-
#define DO_SOMETHING(a, b) a^=b^=a^=b我需要选择一个关于密码的选项-
( a)将参数集中的所有位元转换为
( b)计算两个参数之间的距离
( c)在两个参数交换之间替换
( d)它们是代码中的错误
( e)两个参数之间的乘数
建议答案是c,但我不明白怎么回事。有人能解释吗?
编辑:
我试着运行代码,得到以下输出-
main.c: In function ‘main’:
main.c:3:25: error: lvalue required as left operand of assignment
3 | #define D_(a, b) a^=b^=a^=b
| ^~
main.c:7:20: note: in expansion of macro ‘D_’
7 | printf("%d\n", D_(1, 2));
| ^~发布于 2021-01-25 13:14:26
this question中解释了按位异或操作是如何交换值的。但是,C标准没有定义此处显示的代码的行为,因为C 2018 6.5 2中有此规则:
如果标量对象上的副作用相对于同一个标量对象的不同副作用或使用同一个标量对象的值计算的值没有排序,则行为是未定义的。
在a^=b^=a^=b中,最右边的a^=b是一个复合赋值。它计算左操作数和右操作数(a和b),XOR它们,并生成它将存储在a中的值,以便在表达式中进一步使用。作为副作用,它将该值存储在a中。
然后在b^=a^=b中,这个新的^=采用b和a^=b (上面描述的)的值,XOR它们,并生成它将存储在b中的值。作为副作用,它将该值存储在b中。
最后,在a^=b^=a^=b中,新的^= XOR值与上面生成的值相同。作为副作用,它将该值存储在a中。
现在我们有两个副作用可以修改a。副作用是指与表达式的主计算分开进行的事情。上面引用的规则意味着多个副作用不应该修改同一个对象;应该有东西将它们分开。
分离副作用的一个简单方法是将赋值放在单独的语句中,因为在每个表达式语句之后都有一个序列点:
a ^= b;
b ^= a;
a ^= b;除了关于表达式语句的序列点之外,C还有关于排序的其他规则。例如,赋值语句的一个规则是,更新左操作数的副作用是在运算数的值计算之后进行排序。所以我们知道,在a^=b^=a^=b中,存储到a是在计算b^=a^=b值之后发生的。然而,a^=b中的副作用并不是数值计算的一部分,因此我们不知道a^=b^=a^=b中的副作用是在a^=b的副作用之后排序的。学习这些规则可能需要一段时间,因为其中一些规则很棘手。在大多数情况下,程序员应该通过限制使用带有表达式内部副作用的操作来避免这些操作。
补充说明
此外,我知道还有其他人写了您正在询问的宏,但您应该知道,将宏参数括在宏替换文本中的括号中是一种很好的做法:
#define DO_SOMETHING(a, b) (a)^=(b)^=(a)^=(b)这是因为可以使用不仅仅是简单名称的参数来调用宏,例如使用其他运算符的表达式,并且这些参数可能导致形成与宏作者所期望的结构不同的表达式。(我认为这在这个特定的宏中可能不会发生,因为赋值是除逗号运算符之外的最低优先级运算符,而且逗号运算符在宏参数中不会出现不受保护的情况,因为它将被视为参数分隔符。然而,使用括号仍然是一种良好的做法。
发布于 2021-01-25 13:48:39
答案是c)在两个参数交换之间替换
考虑以下代码
#include <stdio.h>
#define DO_SOMETHING(a, b) a^=b^=a^=b
int main() {
int val1 = 10;
int val2 = 13;
printf("%d\n", DO_SOMETHING(val1, val2));
// printf("%d\n", val1 ^= (val2 ^= (val1 ^= val2))); // macro expansion simplified
printf("val1: %d, val2: %d\n", val1, val2);
return 0;
}此宏在执行XOR时使用复合赋值操作,并结合代码在单个语句中使用XOR操作交换两个值,例如,使用XOR操作的两个交换值a和b如下
a = a^b;
b = a^b;
a = a^b;现在让我们扩展宏a^=b^=a^=b
a^=b^=(a^=b) // a = a^b
a^=(b^=(a^=b)) // b = b^a
a^=(b^=(a^=b)) // a = a^b注意:我们不能将文字值传递给这个宏,因为赋值需要lvalue,所以DO_SOMETHING(3,5)将导致编译错误。
https://stackoverflow.com/questions/65885106
复制相似问题