在没有临时变量的情况下交换 2 个函数指针
Swapping 2 function pointers without a temporary variable
交换两个 void 指针很容易,无需使用任何额外内存:
void* p1;
void* p2;
//...
p1 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
p2 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
p1 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
但是要交换函数指针我必须使用另一个指针吗? (因为不能保证它们适合任何整数类型)。
void (*p1)();
void (*p2)();
//...
void (*tmp)() = p1;
p1 = p2;
p2 = tmp;
谁能给我一个完全可移植的方法示例,该方法无需使用临时变量即可交换函数指针?
我认为这可行,因为允许通过 (unsigned) char 别名:
void (*p1)();
void (*p2)();
for (size_t i = 0; i < sizeof(p1); ++i) {
((unsigned char *)&p1)[i] ^= ((unsigned char *)&p2)[i]
}
for (size_t i = 0; i < sizeof(p2); ++i) {
((unsigned char *)&p2)[i] ^= ((unsigned char *)&p1)[i]
}
for (size_t i = 0; i < sizeof(p1); ++i) {
((unsigned char *)&p1)[i] ^= ((unsigned char *)&p2)[i]
}
使用异或交换算法:
*p1 = *p1 ^ *p2;
*p2 = *p1 ^ *p2;
*p1 = *p1 ^ *p2;
我宁愿这样写(见下文,然而):
uintptr_t up1 = (uintptr_t)p1;
uintptr_t up2 = (uintptr_t)p2;
p1 ^= p2;
p2 ^= p1;
p1 ^= p2;
在大多数具有 sizeof(uintptr_t)
<= 寄存器大小的体系结构上,这是三个指令 == 3 个时钟,可能与其他版本一样多(除非强制转换需要额外费用)。但是,对于大多数架构,我更喜欢临时变量。
警告:它不安全:虽然6.3.2.3p1 states "void *
can be converted safely between a pointer to any object type" and 7.20.1.4p1 states "unitptr_t
can hold a void *
", 3.15限制术语对象 仅用于数据存储。函数驻留在代码存储中。 (感谢评论)
所以,不要将其应用于函数指针!
请注意,这无论如何都没有临时版本那么明显,如果编译器检测到临时版本的模式,它可能会很好地使用此代码。
交换两个 void 指针很容易,无需使用任何额外内存:
void* p1;
void* p2;
//...
p1 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
p2 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
p1 = ((uintptr_t)p1) ^ ((uintptr_t)p2);
但是要交换函数指针我必须使用另一个指针吗? (因为不能保证它们适合任何整数类型)。
void (*p1)();
void (*p2)();
//...
void (*tmp)() = p1;
p1 = p2;
p2 = tmp;
谁能给我一个完全可移植的方法示例,该方法无需使用临时变量即可交换函数指针?
我认为这可行,因为允许通过 (unsigned) char 别名:
void (*p1)();
void (*p2)();
for (size_t i = 0; i < sizeof(p1); ++i) {
((unsigned char *)&p1)[i] ^= ((unsigned char *)&p2)[i]
}
for (size_t i = 0; i < sizeof(p2); ++i) {
((unsigned char *)&p2)[i] ^= ((unsigned char *)&p1)[i]
}
for (size_t i = 0; i < sizeof(p1); ++i) {
((unsigned char *)&p1)[i] ^= ((unsigned char *)&p2)[i]
}
使用异或交换算法:
*p1 = *p1 ^ *p2;
*p2 = *p1 ^ *p2;
*p1 = *p1 ^ *p2;
我宁愿这样写(见下文,然而):
uintptr_t up1 = (uintptr_t)p1;
uintptr_t up2 = (uintptr_t)p2;
p1 ^= p2;
p2 ^= p1;
p1 ^= p2;
在大多数具有 sizeof(uintptr_t)
<= 寄存器大小的体系结构上,这是三个指令 == 3 个时钟,可能与其他版本一样多(除非强制转换需要额外费用)。但是,对于大多数架构,我更喜欢临时变量。
警告:它不安全:虽然6.3.2.3p1 states "void *
can be converted safely between a pointer to any object type" and 7.20.1.4p1 states "unitptr_t
can hold a void *
", 3.15限制术语对象 仅用于数据存储。函数驻留在代码存储中。 (感谢评论)
所以,不要将其应用于函数指针!
请注意,这无论如何都没有临时版本那么明显,如果编译器检测到临时版本的模式,它可能会很好地使用此代码。