-1

Basically I have a hard coded address in decimal value, and I would like to convert that to a pointer, I have been following this link

But I am not getting it to run as I believe my address is being truncated i.e. the 0's in the address are being removed.

Is there any how I can maintain the 0's or is there a way where I can type cast my address stored in buff to a pointer?

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]) {
    int address = 200000000;
    char buff[80];
    sprintf(buff, "0x%012x", address);
    printf("%s\n", buff);

    uint32_t * const Value = (uint32_t *)(uintptr_t)buff;
    // *Value = 10;

    printf("%p\n", Value); // Value is now storing the value of the variable buff, I dont want this

    uint32_t *const Value2 = (uint32_t *)(uintptr_t)0x00000bebc200;

    printf("%p\n", Value2); // my address gets truncated, dont want the address to be truncated
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Weez Khan
  • 137
  • 1
  • 8
  • Use a `uint64_t` instead. – dbush Feb 15 '20 at 13:36
  • @dbush still the address gets truncated while using `uint64_t` – Weez Khan Feb 15 '20 at 13:40
  • 2
    What does “the 0’s in the address are being removed” mean? The zeros on the right (low) side or the zeros on the left (high) side? The zeros on the left do not matter. Showing them is just aesthetic, a matter of how the number is displayed. 0x00000bebc200 and 0xbebc200 are the same number. – Eric Postpischil Feb 15 '20 at 13:42
  • Using an arbitrary address, like 200000000, will not generally work. On general-purpose multi-user operating systems, your process has an address space created by the operating system. The only addresses in that space that are mapped to actual memory are those set up for specific purposes: The instructions in your program, data defined during the building of your program, space for stack, space allocated for dynamic memory allocation, and so on. If you pick an arbitrary address and try to read memory there, you are likely to get an error because the memory is not mapped. – Eric Postpischil Feb 15 '20 at 13:46
  • If you try to write the memory there, you are likely to mess up data that your program is using for some other purpose, or you may get an error because the memory is not mapped or because it is mapped with read-only access. – Eric Postpischil Feb 15 '20 at 13:46
  • @EricPostpischil the 0's on the left(high) side, well if I use this piece of code on my "embedded system" it says the range "0xbebc200" is invalid while if I manually check I know I have not allocated it but I know it is there (assuming 0xbebc200 and 0x00000bebc200 refer to the same location ) – Weez Khan Feb 15 '20 at 13:48
  • @EricPostpischil thank you for the comments, I will check my system and see if my memory is mapped and check its read and write permissions – Weez Khan Feb 15 '20 at 13:50
  • Even if you do have access to that memory, I still don't understand what all that weird code is for. Why don't you use a simpler and more readable approach like `#define MY_MEMORY_AREA ((uint8_t *)(0x0bebc200))` or `#define MY_MMIO_REG *((volatile uint16_t *)(0x0bebc200)`? – Michael Feb 15 '20 at 13:55
  • @Michael well am no expert, Just began my journey in programming embedded systems, Thank you for your suggestion, I will try to utilize it, and the basic code I provided was an extract of my main other code, just to provide a clearer example. – Weez Khan Feb 15 '20 at 13:58
  • Include in your question that desired output and the actual output, because it is not at all clear what your are referring to. Any 32bit value can be represented by 8 hex digits, and the %p format specifier presents the value in a form suited ot teh platform. The _leading_ zeros in 0x00000bebc200 will likely be ignored, and leading zeros are not significant in any case. If your platform uses 64 bit pointers, %p will present 16 digits, on a 32 bit platform, probably only 8 and most 8 bit platforms have 16 bit addresses - only 4 hex digits. And nobody represents addresses in decimal! – Clifford Feb 15 '20 at 19:49

2 Answers2

0

It is not necessary to prevent the truncation of your pointer.

When compiling for 64bit, your pointer will be 64 bit big. This means it holds a number like 0x0123456789ABCDEF.

However, the output formatter %p will drop any leading 0, as they do not change the behaviour of your programm. It is like comparing 0x42==0x0042.


You do not need to convert your address to hex in order to use it as a pointer.

A computer saves your address in binary format. In memory, your address 200000000 will be saved as 0b1011111010111100001000000000.

The output format of decimal and hexadecimal is only used to make it more comfortable for humans to read the output.

The computer does not care, if you supply decimal, hexadecimal or binary numbers, in-memory it will always work with binary representation.

This means that you can directly follow the advice of your linked answer

#include <inttypes.h> // defines PRIxPTR, see comments of @chqrlie and @JonathanLeffler

uintptr_t address= 200000000; // compiler makes sure to convert this to binary for the pc
uint32_t *Pointer = (uint32_t*) address;

printf("0x%" PRIxPTR " address\n", address); // if the ptr size is known, e.g. %lx can be used
printf("%p pointer\n", Pointer);

sprintf converts your number into an ascii string and saves that to buff. That means you cannot cast the content of buff to get back the number. You would need to to an string to int or string to hex conversion before.


Edit:

You can test the conversion of your compiler by printing the following compare statements

 printf("%d\n", address == 200000000); // output true
 printf("%d\n", address == 0xbebc200); // output true
 printf("%d\n", address == 0x00000bebc200); // output true
 printf("%d\n", address == 0b1011111010111100001000000000); // output true
C. Mayer
  • 383
  • 3
  • 10
  • `%lx` might be incorrect for `uintptr_t`, for example on 64-bit Windows, `unsigned long` is 32-bits and `uintptr_t` has 64 bits. – chqrlie Feb 15 '20 at 23:29
  • @chqrlie That's true, however when using a 32bit compiler it is %lx. E.g. Wandbox is using ```long unsigned int``` for ```uintptr_t```.As the question is tagged ```embedded``` it's not unlikely to have an 32bit system. – C. Mayer Feb 16 '20 at 00:09
  • @C.Mayer: If you are certain that the target is 32-bits, why bother with `uintptr_t`? If you use `uintptr_t`, you should cast the variable: `printf("0x%lx address\n", (unsigned long)address);` as there is not portable `printf` format for this type. – chqrlie Feb 16 '20 at 00:14
  • @chqrlie: the portable format for `uintptr_t` is in `` and is `PRIxPTR` or `PRIXPTR` (assuming you want hex — replace `x` with `u` or `o` if you want decimal or octal). – Jonathan Leffler Feb 16 '20 at 00:46
  • @JonathanLeffler: indeed one should write `printf("0x%"PRIxPTR" address\n", address);` – chqrlie Feb 16 '20 at 02:06
0

If %p presents only 8 hex digits for the address, then that is because a pointer on your platform is only 32 bits and in that case the leading zeros have no meaning as there are no address bus lines A32 to A40 to set to zero. The bits are not "truncated", they are not there in they first place.

If you some odd reason you wish to present the address as 48 bits (12 hex digits) on a platform where 32 bits is sufficient then:

uintptr_t address = 200000000u ;
uint32_t* const Value = (uint32_t *)address ;
printf( "0x%12.12lX\n", (uintptr_t)Value ) ;

Outputs:

0x00000BEBC200 

But that is only a matter of presentation, the value in address and Value are unchanged and remain 32 bits.

Clifford
  • 88,407
  • 13
  • 85
  • 165