3

As part of a program for a class, I have to print the output a specific way, split up into blocks of sixteen bytes. I've been searching for quite a while for a way to cast the pointer to an int or another way to perform a modulus or division remainder operation on the pointer address stored in a variable. I've hit a roadblock, does anyone here know how I could perform this seemingly simple operation? Here's the basic form of the function:

void printAddress(char *loc, char *minLoc, char *maxLoc) {
    minLoc = (loc - (loc % 16));
    maxLoc = minLoc + 16;
    printf("%p - %p - %p", minLoc, loc, maxLoc);
}

I removed all my attempts at casting it to make it clear what I'm trying to do.

ZapTap
  • 125
  • 2
  • 2
  • 11
  • Can you clarify more what you intend to do? – brokenfoot Mar 22 '14 at 22:08
  • I'm just a bit confused on your requirements. You said you need to output your data in blocks of sixteen bytes, but this function doesn't even start to display a block of that size...am I just misunderstanding? If you could clarify, it'd be helpful! – David W Mar 22 '14 at 22:09
  • Yes, I'm sorry! I just did the part about finding the start and end of the block so far. I have the content of a text file stored in memory and I'm searching for an ascii value given by the character. When I find it, I print the character's address and the data surrounding it starting at an address that is a multiple of 16. So if it were at low addresses, loc could point to an address of 26, in which case I would need to print the block of addresses from 16 to 31. – ZapTap Mar 22 '14 at 22:14
  • 1
    One of your problems is that you're trying to print integer representations of your pointers. The correct conversion specifier for pointer is `%p` – ciphermagi Mar 22 '14 at 22:17
  • @ciphermagi I fixed that in the question - I still need to find the bounds of the block, though. – ZapTap Mar 22 '14 at 22:24
  • Make a new pointer and move backwards in memory. Although if you're trying to do what you've described, it's a Very Bad Thing, since you could easily go outside of your bounds. I'm wondering if maybe you mean that it's supposed to print everything from *index* %16 to *index* %31 instead of *address*? – ciphermagi Mar 22 '14 at 22:29
  • @ciphermagi I'm only printing things that are included in the string - if the block exceeds the bounds of the string at either the beginning or end, I'm not printing anything held there, but indicating that it is outside the bounds. So if the string starts with "Sometexthereblahblahmorecharactersetcetc", the last two c's would print only characters 32-39, and then indicate that the rest of the block is outside of the string. – ZapTap Mar 22 '14 at 22:36
  • The point that I'm trying to get at is that moving around in memory is *dangerous* because you could easily access bounds outside the array. If, however, you know where your array starts && ends, then you can simply print from indices, and the solution is simply to keep track of what index you're currently in, then reduce your index, *not* your address to the nearest multiple of 16. Reducing the address *does not check* to see whether or not you're still in the array. – ciphermagi Mar 22 '14 at 22:39
  • @ciphermagi I see what you're saying. That's a better way to do it, even. But I do still need to find at least one point where it reaches an address that's divisible by 16, so I know which part of the array to print. That's the least I can get away with doing in this program, since one of the required functions is to print the data in an address range specified by the user. – ZapTap Mar 22 '14 at 22:47

2 Answers2

6

The type you're looking for is uintptr_t, defined in <stdint.h>. It is an unsigned integer type big enough to hold any pointer to data. The formats are in <inttypes.h>. They allow you to format the code correctly. When you include <intttypes.h>, it is not necessary to include <stdint.h> too. I chose 16 assuming you have a 64-bit processor; you can use 8 if you're working with a 32-bit processor.

void printAddress(char *loc)
{
    uintptr_t absLoc = (uintptr_t)loc;
    uintptr_t minLoc = absLoc - (absLoc % 16);
    uintptr_t maxLoc = minLoc + 16;
    printf("0x%16" PRIXPTR " - 0x%16" PRIXPTR " - 0x%16" PRIXPTR "\n",
           minLoc, absLoc, maxLoc);
}

You could also write:

    uintptr_t minLoc = absLoc & ~(uintptr_t)0x0F;

See also Solve the memory alignment in C interview question that stumped me.

Note that there might, theoretically, be a system where uintptr_t is not defined; I know of no system where it cannot actually be supported (but I don't know all systems).

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Now, are there any drawbacks to using this method? or will it just be treated, for all intents and purposes, as any other integer type? – ZapTap Mar 22 '14 at 22:52
  • 2
    The point of uintptr_t is to treat a pointer as a plain unsigned integer type. – Pod Mar 22 '14 at 22:54
  • 1
    Actually, looking into it more, I think "any" mutation to a uintptr_t that is then cast back to a pointer is "undefined behaviour" when that pointer is dereferenced, because you might be voided all sorts of internal alignment stuff the compiler has done behind your back. It won't be in 99.99% of the cases though ;) – Pod Mar 22 '14 at 22:59
  • `uintptr_t` is a plain old unsigned integer type; it is specifically specified by the system as a type, not necessarily a standard type, that is big enough to hold data pointers. If the system uses 96-bit data pointers and supports a 128-bit unsigned integer type, then `uintptr_t` might be an alias for that 128-bit unsigned type. – Jonathan Leffler Mar 22 '14 at 23:04
  • 1
    @Pod: you are treading on thin ice if you modify the value so it goes out of bounds of whatever array (or value) the pointer points at initially. If your modification leaves the modified value within the boundaries of the array and with an appropriately aligned value, you're extremely unlikely to run into problems. But it is, theoretically, a portability liability, so you'd carefully ghettoize the code in the part of your system that gets scrutinized for portability assumptions when you do migrate it. – Jonathan Leffler Mar 22 '14 at 23:08
0

I might not fully understood the problem, but for me it looks as if you are trying to do the good old hexdump?

void hexdump(char *buf, int size)
{
    int i;

    for (i = 0; i < size; i++)
    {
        if (i % 16 == 0)
        {
            puts("");
            printf("%p", &buf[i]);
        }

        printf("%02x ", buff[i]);
    }
}
mfro
  • 3,286
  • 1
  • 19
  • 28