在没有临时变量的情况下交换 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限制术语对象 仅用于数据存储。函数驻留在代码存储中。 (感谢评论)

所以,不要将其应用于函数指针!

请注意,这无论如何都没有临时版本那么明显,如果编译器检测到临时版本的模式,它可能会很好地使用此代码。