在C

时间:2015-06-17 12:10:12

标签: c pointers swap

我需要在C中执行两个指针的超高性能交换(地址,而不是他们指向的地址)。我知道地址是对齐的(16的倍数)和连续的,我已经检查过这在每次执行时都会保留。代码如下:

Nodo a __attribute__((aligned(8))), b __attribute__((aligned(4)));
Nodo *nodo_superior __attribute__((aligned(4)));
nodo_superior = &a;
Nodo * nodo_actual __attribute__((aligned(4)));
nodo_actual=&b;
printf("%ld %ld\n", nodo_superior, nodo_actual);

并且控制台上的结果就像(请注意,第一个地址应该是“over” - 对齐,以便下一个方法起作用):

140594404335200 140594404335216

现在要交换地址,我想更改每个指针的第5位:

nodo_superior ^= 16; 
nodo_actual ^= 16;

但是,遗憾的是C编译器不允许这样做,因为整数不能与指针值混合:它是一个错误,而不是一个警告。如果我尝试将指针包含在这样的联合中:

union {
    Nodo * nodo_actual;
    int local_int;
} na;

想要做一个像:

这样的分配
na.local_int ^= 16;

然后性能下降,因为(我想)如果编译器在联合中,则编译器不能对nodo_actual应用/推断优化。 任何强迫编译器按我的意愿行事的想法?当然,我可以更改生成的汇编程序,但我认为这不是一个好的选择,

3 个答案:

答案 0 :(得分:2)

如果你想切换每个指针的第5位,你可以写:

nodo_superior = (Nodo *)((uintptr_t)nodo_superior ^ 16);

uintptr_t是一种整数类型,如果存在,则保证能够保存指针值而不会丢失信息。

它的意图是通过平坦内存模型上的明显同构来完成,所以它应该适合你(尽管首先要测试它)。

此外,您应该使用%p来打印指针,而不是导致未定义行为的%ld。打印uintptr_t see here

答案 1 :(得分:2)

交换更好地使用临时变量“旧方式”执行。

SELECT a.name, Count(1) AS TotalCount
FROM allData a
WHERE EXISTS(SELECT TOP 1 1 FROM relevantData WHERE a.name = name)
GROUP BY a.name

这需要2次读取和2次写入。

“智能”解决方案

Nodo* Swap= a; a= b; b= Swap;

需要2次读取,2次读取和2次写入。

答案 2 :(得分:0)

我不确定我真的明白“交换两个指针”是什么意思。您似乎有一对节点,并且您希望计算一个节点的地址来自另一个节点的地址。

类似的问题是当你有两个数字时(例如1和2为球员号码)并想要将球员数量从1更改为2,反之亦然。通常的技巧是计算

  opponent = (1+2) - player ;

你可以用指针玩类似的技巧,因为允许一些算法:

int main(int argc, char **argv)
{
    struct Node x;
    struct Node y;

    printf("x is at %p,  y at %p\n", &x, &y);

    struct Node * one = &x;
    struct Node * other = &x + (&y - one); // (&x + &y) - one

    printf("if one is at %p,  the other is at %p\n", one, other);

    one = &y;
    other = &x + (&y - one);

    printf("if one is at %p,  the other is at %p\n", one, other);

    return 0;
}