Pages: [1]   Go Down
Author Topic: Need to print pointer address to uart without using printf or sprintf  (Read 3972 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

I would like to print a pointer address to the uart without using printf or sprintf with %p parameter. Is this possible? Including these functions takes up too much space in my bootloader. I have found Can you store the pointer address in a variable and print that out? The only function that I have to print to uart is putchar(char ch).

Thanks,

-ren
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What system are you using, I don't think those functions are implemented on Arduino.

To print the address  of something on Arduino do something like

int x;

Serial.println (&x, HEX);

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 5
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can you store the pointer address in a variable and print that out?

If you want to print the value of a pointer without using the format %p specifier, you can cast the pointer to an integer that has the same size and then print the integer value.

To print the address  of something on Arduino do something like

int x;
Serial.println (&x, HEX);

Actually, you can't do this without a cast.  (Did you try it?)

The Arduino print functions do not have a version that is defined to print a pointer to int.

The sketch is compiled as part of a C++ program, and C++ enforces a certain amount of data type integrity. The C++ compiler won't let you assign a pointer value to some non-pointer data type, so you have to use a cast of some kind.  For me, the simplest is just an old C-style cast.

The only thing is that you have to make sure the size of the integer data type is the same size as the pointer, so the method is not portable.
In other words, when you are casting a pointer to another data type it is up to you to make sure they are commensurate.

Now, with avr-gcc (Arduino's compiler) the size of an int is two bytes and the size of a pointer is two bytes.

You can verify this by running something like the following.  Note that sprintf does support printing with %p format specifier, so I use that to compare output with various ways of using casts.

Code:
// Printing pointer values
//   davekw7x

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    char buffer[30];
    char x[3] = "Hi";
    char *y;
    int z;
    sprintf(buffer, "with %%p:  x    = %p\n", x);
    Serial.print(buffer);
    sprintf(buffer, "with %%p: &x[0] = %p\n", &x[0]);
    Serial.print(buffer);

    y = &x[0]; // Same as writing y = x;
    z = (unsigned int)y;
    Serial.print("sizeof(unsigned int) = ");Serial.print(sizeof(unsigned int));
    Serial.print(", sizeof(char *) = "); Serial.println(sizeof(char *));
    Serial.print("(unsigned int)y     = 0x");Serial.println(uint16_t(y),HEX);
    Serial.print("(unsigned int)x     = 0x");Serial.println((unsigned int)x,HEX);
    Serial.print("(unsigned int)&x[0] = 0x");Serial.println((unsigned int)&x[0],HEX);
    Serial.print(" z = 0x");Serial.println(z,HEX);
    Serial.print("&z = 0x");Serial.println((unsigned int)&z, HEX);

    Serial.println();
    delay(10000);
}


Output:

with %p:  x    = 0x8d5
with %p: &x[0] = 0x8d5
sizeof(unsigned int) = 2, sizeof(char *) = 2
(unsigned int)y     = 0x8D5
(unsigned int)x     = 0x8D5
(unsigned int)&x[0] = 0x8D5
 z = 0x8D5
&z = 0x8D3



Bottom line: Whatever method you use to put integer values to your uart can be used to put pointer values.  At the receiving end, the program reading the integer value can cast it to a pointer type and use it for whatever it needs to do.

Regards,

Dave
Footnote:
Note that sprintf with "%p" always prints hex and the version in avr-libc (like all GNU compiler libraries that I have used) always puts "0x" in front of it.  By using a cast to unsigned int instead of sprintf, you can print with whatever base you want.  As long as the sender and receiver agree on the exact format, All is Good.
« Last Edit: March 28, 2011, 10:41:21 am by davekw7x » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Being able to do something does not mean that it is smart to do it. Typically, pointers are useful only on the system they were defined on. So, what value does the pointer you are trying to send have on another system? In other words, why are you trying to write a pointer's address to the serial port?
Logged

Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using only putchar():

Code:
  int ptr = (int) &value;                 // store 16-bit address, and then pretend that memory is a character array
  putchar( *(1+ (unsigned char*) &ptr) ); // MSB
  putchar( *( (unsigned char*) &ptr) );   // LSB
Logged

Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Or as ASCII text:

Code:
  int ptr = (int) &value;                 // store 16-bit address, and then pretend that memory is a character array
  unsigned char tmp;
  char string[]="0123456789ABCDEF";

  tmp = *(1+ (unsigned char*) &ptr); // MSB
  putchar( string[tmp >> 4] );
  putchar( string[tmp & 0xF] );

  tmp = *(0+ (unsigned char*) &ptr); // LSB
  putchar( string[tmp >> 4] );
  putchar( string[tmp & 0xF] );
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow,

Thanks for the replies. I wasn't sure if I would get any. Looks like I will have something to try out later today when I get back home.

The pointer is a uint8_t *, which I believe is an unsigned char. Any ideas on to put that to the putchar(char ch)?

To answer your questions. Can't use Serial.print, I am in the bootloader. I am not planning on using ptr address for my program, just debugging code, trying to figure what is going in a bootloader that I downloaded from internet.

Thanks,

-ren
Logged

Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The code above should be OK since the pointer will be a 16-bit address, no matter what variable-type it points to.  I suppose the pointer ought to be unsigned. eg.
Code:
uint8_t value
uint16_t ptr = (uint16_t) &value;  // store 16-bit address of 'value'
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How do you know that the pointer will be a 16-bit address? I looked at the avr-libc pages. They indicate that a uint16_t is an unsigned integer and is 16 bit. On some other places on the internet an unsigned integer is a 4 byte variable (or 32 bit). Not sure why there is a difference here, maybe depends on the system you are using the variable on.

The pointer value that I am trying to display is iterating. I try to display it after each iteration, but the value doesn't update when outputed to uart. Are there issues regarding outputing a pointer at runtime?

Thanks,

-ren
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
How do you know that the pointer will be a 16-bit address?
Because in an 8-bit AVR it is, in fact it's less than that on most AVR chips.

Quote
On some other places on the internet an unsigned integer is a 4 byte variable (or 32 bit). Not sure why there is a difference here, maybe depends on the system you are using the variable on.
An unsigned int is not a pointer. But you are right, the size of ints and pointers depends on the system.

Quote
I try to display it after each iteration, but the value doesn't update when outputed to uart. Are there issues regarding outputing a pointer at runtime?
No, once cast (which I forgot to do in my example ) to an int it will print properly.

Quote
The pointer value that I am trying to display is iterating.
You don't "iterate" a value, do you mean "increment on each iteration of a loop"?

Show us the code you are using.

______
Rob



Logged

Rob Gray aka the GRAYnomad www.robgray.com

Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How do you know that the pointer will be a 16-bit address? I looked at the avr-libc pages. They indicate that a uint16_t is an unsigned integer and is 16 bit. On some other places on the internet an unsigned integer is a 4 byte variable (or 32 bit). Not sure why there is a difference here, maybe depends on the system you are using the variable on.

A pointer is just a memory address, so the size of the variable storing the pointer value has to match the size of the memory address.  I was assuming you were using an ATmega328 or 168, which have 16-bit memory addresses.  So my code would not work on a processor with a larger memory space.  A uint16_t is always 16-bit by definition, whereas the size of an int varies depending on the platform and compiler.

Quote
The pointer value that I am trying to display is iterating. I try to display it after each iteration, but the value doesn't update when outputed to uart. Are there issues regarding outputing a pointer at runtime?

You'll need to re-read the pointer each time it changes.  So after every iteration you'll need to do this line before writing to the serial port:
Code:
uint16_t ptr = (uint16_t) &value;  // store 16-bit address of 'value'
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, sorry, I meant increment.

I partially understand the code below, could you explain a little bit more on what is going on? Still kind of fuzzy on the bit-math.

   int ptr = (int) &value;                 // store 16-bit address, and then pretend that memory is a character array
  unsigned char tmp;
  char string[]="0123456789ABCDEF";

  tmp = *(1+ (unsigned char*) &ptr); // MSB
  putchar( string[tmp >> 4] );
  putchar( string[tmp & 0xF] );

  tmp = *(0+ (unsigned char*) &ptr); // LSB
  putchar( string[tmp >> 4] );
  putchar( string[tmp & 0xF] );
---------
   int ptr = (int) &value;                 // store 16-bit address, and then pretend that memory is a character array
  putchar( *(1+ (unsigned char*) &ptr) ); // MSB
  putchar( *( (unsigned char*) &ptr) );   // LSB


Thanks,
-ren
Logged

Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

These versions may be slightly clearer.  They avoid typecasting the integer into a character array.  See any C reference for an explanation of the '>>' and '&' operators.

This writes out the address as a binary number
Code:
/* initialisation */
uint16_t ptr;

/* these lines go inside the loop */
ptr = (uint16_t) &value;               // store 16-bit address of 'value'
putchar( (char) (ptr >> 8) & 0xFF );   // Write out high-byte of memory address
putchar( (char) (ptr >> 0) & 0xFF );   // Write out low-byte of memory address

This writes out the address as human-readable hexadecimal text
Code:
/* initialisation */
char string[]="0123456789ABCDEF";       // array of characters corresponding to numbers from 0 to 15
uint16_t ptr;

/* these lines go inside the loop */
ptr = (uint16_t) &value;                // store 16-bit address of 'value'
putchar( string[ (ptr >> 12) & 0xF ] ); // Write out highest 4-bits of memory address
putchar( string[ (ptr >>  8) & 0xF ] );
putchar( string[ (ptr >>  4) & 0xF ] );
putchar( string[ (ptr >>  0) & 0xF ] ); // Write out lowest 4-bits of memory address
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Graynomad, davekw7x, and especially tim7 for your help! Great replies!
Logged

Pages: [1]   Go Up
Jump to: