在C中更改二进制地址中的一个给定位

时间:2015-09-30 07:41:01

标签: c memory memory-management binary

我正在进行"伙伴分配"用于C中的内存管理项目(参见page 14 of this .pdf)。

我想找到"好友"对于给定地址,知道两个伙伴只有一位不同(块的大小告诉我们哪个位发生了变化)。例如,如果两个32位伙伴块中的一个具有二进制地址0b110 0 10100,则第二个将位于0b110 1 10100(来自第6位)正确的变化,如32 = 2 ^(6-1))。

我想在没有取幂算法的情况下在C中实现它,因为我试图让我的程序尽可能快地执行。充其量我会使用工具来操作位,如果存在的话。任何提示?

编辑:地址类型为 void * 。通过下面发布的解决方案, gcc 不会让我编译。

EDIT2:我已经尝试过使用XOR运算符发布的下面的答案,但由于地址的类型,我无法编译。以下是我尝试过的内容:

INSERT INTO tablename (id, ip, total) VALUES (1, xxx.xxx.x.x, 1)
ON DUPLICATE KEY UPDATE total = total+1;

gcc 错误:

void* ptr1 = mmap(NULL, 640000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_FILE | MAP_PRIVATE, -1, 0);
    printf("%p\n", ptr1);
    void* ptr2 = ptr1+0x15f6d44;
    printf("%p\n", ptr2);
    void* ptr3 = (void*)(ptr2-ptr1);
    printf("%p\n", ptr3);
    void* ptr4 = ptr3 ^ (1 << 6);
    printf("%p\n", ptr4);

5 个答案:

答案 0 :(得分:4)

看起来您只想切换给定位,这是使用XOR操作实现的:

buddy_adr = (unsigned long)adr ^ (1 << bit_location);

需要转换为unsigned long以避免类型void*上的未定义XOR操作错误。

根据您的编译器设置,您可能还会收到有关通过转换整数来创建指针(即地址)的警告,这在一般情况下显然很危险(您可以传递无效的地址值)。要将此警告静音,请将结果转回void*,让编译器知道您知道自己在做什么:

buddy_adr = (void *)((unsigned long(adr ^ (1 << bit_location));

请注意,在嵌入式系统编程中(我大部分时间都使用过这种技术,因为许多外设都是内存映射的),你通常可以简化&#34;这行代码使用TOGGLE_BIT(addr, bit)INT_TO_ADDR(addr)等宏。

答案 1 :(得分:3)

您可以按位|或。

设置一位
adr = adr | 0x10;

答案 2 :(得分:3)

一个工具?操纵位?你不需要一个&#34;工具&#34;,这就像你可以做的原始操作一样。

uint32_t address = 0x0194;

address |= 1 << 5; /* This sets the sixth bit. */

如果你真的想切换这个位,即设置它是否清除,但如果设置清除它,则使用按位XOR运算符:

address ^= 1 << 5;

这是&#34;取词&#34;,它只是一个按位异或。

如果地址保存在指针寄存器中,则转换或复制到整数(uintptr_t)并复制回来。

答案 3 :(得分:2)

这是位操作的情况,这在c编程中非常常见 如果你想改变xxbxxxxx,只需用xx1xxxxx对此进行异或。 XOR推翻给定位。如果你想使它1只使用OR(|)所有位0,除了你要打开的位1

答案 4 :(得分:1)

更简洁的方法

#define BIT_ON(x,bit)           (x |= ( 1 << (bit-1)) )
#define BIT_TOGGLE(x,bit)       (x ^= ( 1 << (bit-1)) )
#define BIT_OFF(x,bit)          (x &= ~( 1 << (bit-1)) )