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.

9
  • Can you clarify more what you intend to do? Commented Mar 22, 2014 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! Commented Mar 22, 2014 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. Commented Mar 22, 2014 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 Commented Mar 22, 2014 at 22:17
  • @ciphermagi I fixed that in the question - I still need to find the bounds of the block, though. Commented Mar 22, 2014 at 22:24

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

5 Comments

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?
The point of uintptr_t is to treat a pointer as a plain unsigned integer type.
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 ;)
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.
@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.
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]);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.