我正在尝试解决以下问题:
/*
* Return 1 if ptr1 and ptr2 are within the *same* 64-byte aligned
* block (or word) of memory. Return zero otherwise.
*
* Operators / and % and loops are NOT allowed.
*/
/*
我有以下代码:
int withinSameBlock(int * ptr1, int * ptr2) {
// TODO
int temp = (1 << 31) >> 25;
int a = ptr1;
int b = ptr2;
return (a & temp) == (b & temp);
}
我被告知这正确地解决了这个问题,但我不确定它是如何工作的。具体来说,行int temp = (1 << 31) >> 25;
如何帮助解决问题?
答案 0 :(得分:4)
该行:
int temp = (1 << 31) >> 25;
不正确或触发未定义的行为(取决于wordsize)。只是碰巧机器上的未定义行为和编译器做了正确的事情 而恰好给出了正确的答案。为了避免未定义的行为并使代码更清晰,您应该使用:
int withinSameBlock(int * ptr1, int * ptr2) {
uintptr_t temp = ~(uintptr_t)63;
uintptr_t a = (uintptr_t)ptr1;
uintptr_t b = (uintptr_t)ptr2;
return (a & temp) == (b & temp);
}
答案 1 :(得分:3)
我不确定你在哪里获得该代码(作业?)但这太可怕了。
1.铸造指向int和做算术的指针一般是非常糟糕的做法。实际大小未被这些原始类型定义,为了即时,它在指针或int
不是32位的每个架构上都会中断。
你应该使用uintptr_t
,它通常大于或等于指针的大小(除了ambigous spec允许的理论拱形)
例如:
#include <stdint.h>
#include <stdio.h>
int withinSameBlock(int * ptr1, int * ptr2) {
uintptr_t p1 = reinterpret_cast<uintptr_t>(ptr1);
uintptr_t p2 = reinterpret_cast<uintptr_t>(ptr2);
uintptr_t mask = ~ (uintptr_t)0x3F;
return (p1 & mask) == (p2 & mask);
}
int main() {
int* a = (int*) 0xdeadbeef;
int* b = (int*) 0xdeadbeee;
int* c = (int*) 0xdeadc0de;
printf ("%p, %p: %d\n", a, b, withinSameBlock(a, b));
printf ("%p, %p: %d\n", a, c, withinSameBlock(a, c));
return 0;
}
答案 2 :(得分:2)
首先,我们需要明确的是,代码仅适用于指针为32位且int
也为32位的系统。在64位系统上,代码将失败。
左移(1 << 31)
设置int
的最重要位。换句话说,行
int temp = (1 << 31);
与
相同int temp = 0x80000000;
由于int
是有符号数,因此最高有效位是符号位。向右移动带符号的数字将符号位复制为低位。因此向右移动25次会产生一个在高26位中具有1
的值。换句话说,行
int temp = (1 << 31) >> 25;
与(如果写成的话会更清楚)相同(
)int temp = 0xffffffc0;
该行
return (a & temp) == (b & temp);
比较a
和b
的高26位,忽略低6位。如果高位匹配,则a
和b
指向同一块内存。
答案 3 :(得分:1)
假设有32位指针,如果两个指针位于同一个64字节的内存块中,那么它们的地址只会在6个最低有效位中发生变化。
(1 << 31) >> 25
会给你一个如下所示的位掩码:
11111111111111111111111111000000
a=ptr1
和b=ptr2
将a
和b
设置为等于指针的值,即指针的内存地址。 temp
与其中每一个(即a&temp
和b&temp
)的按位AND将屏蔽a
和{{1}所拥有的地址的最后6位}。如果剩余的26位相同,那么原始地址必须彼此相差64个字节。
演示代码:
b