简体   繁体   中英

How to get the actual address of a pointer in C?

BACKGROUND:
I'm writing a single level cache simulator in C for a homework assignment, and I've been given code that I must work from. In our discussions of the cache, we were told that the way a small cache can hold large addresses is by splitting the large address into the position in the cache and an identifying tag. That is, if you had an 8 slot cache but wanted to store something with address larger than 8, you take the 3 (because 2^3=8) rightmost bits and put the data in that position; so if you had address 22 for example, binary 10110, you would take those 3 rightmost bits 110, which is decimal 5, and put it in slot 5 of the cache. You would also store in this position the tag, which is the remaining bits 10.

One function, cache_load, takes a single argument, and integer pointer. So effectively, I'm being given this int* addr which is an actual address and points to some value. In order to store this value in the cache, I need to split the addr. However, the compiler doesn't like when I try to work with the pointer directly. So, for example, I try to get the position by doing:
npos=addr%num_slots

The compiler gets angry and gives me errors. I tried casting to an int, but this actually got me the value that the pointer was pointing to, not the numerical address itself. Any help is appreciated, thanks!

[edit]

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);

When addr is passed in, it's actual address is 58, and it points to a value of 88. The output I'm getting from that printf is:

addr is 58, taddr is 58, npos is 0 and ntag is 11

So it seems taddr is getting 58 (when printed with %p, still shows 88 when printed with %d), but npos and ntag are showing up as 0 and 11 (as though the mathematical operations are being run with 88) instead of 2 and 7 as I'd like.

The code is used like this:

void load_words (int n, int words[]) {
  int i;
  for (i=0; i<n; i++) {
    load( (int *) (words[i] * 4));
    cache_print();
  }
}

You should use something like

int *pointer;
intptr_t address=(intptr_t) pointer;

and this is mainly just a correction on @Andrew's post

So your function should become

(oops forgot this was homework. I'll roll back this question in a while. Can't straight give you the answer :) )

C99标准表示从指针类型到整数类型的转换(反之亦然)是实现定义的行为(6.3.2.3.5和6.3.2.3.6),除非使用<stdint.h>定义的intptr_tuintptr_t但是7.18.1.4说这两种类型不是强制性的,并且实现不需要提供它们。

int *pointer;
uint32_t address = (uint32_t) pointer;

Except of course, you have no guarantee that an int* fits in an uint32_t, so you need to pick the right types for your platform.

Decimal 88 is 0x58 (hex 58). When you use the %p specifier with printf, the hex representation is printed out. So both addr and taddr are decimal 88, and your calculations are correct.

One important thing not already mentioned here. When you print a pointer with the %p specifier, then you should cast the argument:

printf("addr is %p\n", (void *)addr);

%p expects a pointer to void, and a specifier/argument mismatch for printf is undefined behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM