背景:
我正在C中编写一个单级缓存模拟器来完成作业,我已经获得了必须使用的代码。在我们对缓存的讨论中,我们被告知小缓存可以容纳大地址的方式是将大地址分成缓存中的位置和识别标记。也就是说,如果你有一个8槽缓存但想要存储地址大于8的东西,你可以取3(因为2 ^ 3 = 8)最右边的位并将数据放在那个位置;因此,如果您有地址22,例如二进制10110,您将获取那些最右边的位110,即十进制5,并将其放入缓存的插槽5中。您还可以在此位置存储标记,即剩余的位10。
一个函数cache_load接受一个参数和整数指针。所以有效的是,我正在给这个int * addr这是一个实际的地址,并指向一些值。为了将此值存储在缓存中,我需要拆分addr。但是,当我尝试直接使用指针时,编译器不喜欢。所以,例如,我试图通过这样做来获得这个位置:
npos=addr%num_slots
编译器生气并给我错误。我尝试转换为int,但这实际上得到了指针指向的值,而不是数字地址本身。任何帮助表示赞赏,谢谢!
[编辑]
int load(int * addr) {
int value = (use_memory ? (*addr) : 0);
intptr_t taddr=(intptr_t) addr;
int npos=taddr % blocks;
int ntag=taddr / blocks;
printf("addr is %p, taddr is %p, npos is %d and ntag is %d\n",addr,taddr,npos,ntag);
当传入addr时,它的实际地址是58,它指向值88.我从该printf得到的输出是:
addr为58,taddr为58,npos为0,ntag为11
所以似乎taddr得到58(当用%p打印时,在用%d打印时仍然显示88),但是npos和ntag显示为0和11(好像数学运算用88运行)而不是我喜欢的2和7。
代码的使用方式如下:
void load_words (int n, int words[]) {
int i;
for (i=0; i<n; i++) {
load( (int *) (words[i] * 4));
cache_print();
}
}
答案 0 :(得分:4)
您应该使用类似
的内容int *pointer;
intptr_t address=(intptr_t) pointer;
这主要只是对@ Andrew的帖子的修正
所以你的功能应该成为
(哎呀忘了这是作业。我会在一段时间内回复这个问题。不能直接给你答案:))
答案 1 :(得分:4)
C99标准表示从指针类型到整数类型的转换(反之亦然)是实现定义的行为(6.3.2.3.5和6.3.2.3.6),除非使用intptr_t
或{在uintptr_t
中定义了{1}},但7.18.1.4说这两种类型不是强制性的,实现不需要提供它们。
答案 2 :(得分:0)
int *pointer;
uint32_t address = (uint32_t) pointer;
除此之外,您无法保证int *适合uint32_t,因此您需要为您的平台选择正确的类型。
答案 3 :(得分:0)
十进制88是0x58(十六进制58)。将%p说明符与printf一起使用时,将打印出十六进制表示。所以addr和taddr都是十进制的88,你的计算是正确的。
答案 4 :(得分:0)
这里没有提到的一件重要事情。当您使用%p说明符打印指针时,您应该转换参数:
printf("addr is %p\n", (void *)addr);
%p期望指向void,而printf的说明符/参数不匹配是未定义的行为。