Why is this pointer related code not compiled?

Being inspired by Code::Blocks C Compiler (given in Step-2), I wanted to show the pointer value on the Serial Monitor by uploading the following sketch in Arduino UNO. Unfortunately, the Serial.print(ptr, HEX) line fails to get compiled! Would appreciate to recieve guidance in correcting the said line.

1. Arduino Sketch

void setup() 
{
  Serial.begin(9600);
  byte x = 25;
  byte *ptr;
  ptr = (byte*)&x;
  Serial.print(ptr, HEX);  //this line is not compiled.
}

void loop() 
{
  
}

2. Program for IBMPC
Code::Blocks' working codes in my IBMPC.

   #include<stdio.h>
   int main()
   {
      int data = 2018915346; //0x78563412; in my PC an int is 4-byte wide.
      char *ptr;     
      ptr = (char*) &data;   //char = 1-byte; 
      printf("%x\n", ptr);  //shows: 0x0061FE10 that points m0 location

     return 0;
   }

The Print class doesn't know how to print a pointer variable's value. Try:

Serial.print((uint16_t) ptr, HEX)

Why are you casting that? ptr is already a byte *.

With (uint16_t) cast, the line is compiled; but, the printed value (0x21FA) does not make sense to me as it lies outside RAM space (0x0100 - 0x08FF). The variable/identifier x is supposed to represent the content of a memory location which is within the RAM space.

You should really use %p, or cast ptr to an integer type.

I casted ptr to char; beacuse, I have wanted to read 1-byte data from a 4-byte wide memory space of type int in my IBMPC (not UNO).
memAdr
Program for IBMPC

    #include<stdio.h>
    {
       int data = 2018915346; //0x78563412
       char *ptr;
       ptr = (char*) &data;   //char = 1-byte; default int
       printf("%x\n", ptr);  //shows: 0x0061FE10 and point m0
       //-------------------
       char z0 = *ptr;
       printf("%x\n", z0);    //shows: 0x12 = content of m0 location
       //------------------------
       return 0;
    }

With %p, the print shows: 000000000061FE10. To me %x is comfortable as it shows a 32-bit value.

How do you expect 2018915346 to fit into a 16-bit int??

In Step-2 of my Post-1, I have mentioned that in my PC (where I run Code::Blocks Compiler) an int type is 4-byte wide. The printf("%d", sizeof(int)) commands shows 4. In UNO, the int type is a 2-byte wide memory space.

One of us has a serious misunderstanding about the Uno.

The compiler TOLD you why:

In function 'void setup()':
sketch_jan25a:7:24: error: no matching function for call to 'print(byte*&, int)'
   Serial.print(ptr, HEX);  //this line is not compiled.
                        ^

It can't find a Serial.print() function that takes a "byte * &" as a first argument.

The compiler looks at every reasonable possibility:
Serial.print(unsigned char, int)
Serial.print(int, int)
Serial.print(unsigned int, int)
Serial.print(long int, int)
Serial.print(unsigned long int, int)

In no case can it find a way to convert your "byte * &" to any value Serial.print() can use as a first argument.

That means that line (Serial.print(ptr, HEX) is beyond correction in the Arduino UNO Platform! As a result, it is not possible to deliver complete lesson on pointer variable using UNO Learning Kit.

The compiler might have made some optimization given the code is super simplistic so i would not jump to conclusions


void setup() 
{
  Serial.begin(115200);
  byte x = 25;
  byte *ptr;
  ptr = &x;
  Serial.print((uint16_t) ptr, HEX);  
}

void loop() {}

Did you run this on your UNO or in a simulator of some sort? In wokwi simulator it says 8FB which seems reasonable

Probably best to use:

Serial.print(reinterpret_cast<uintptr_t>(ptr), HEX);

so it works on 32-bit and 64-bit systems as well.

This type is optional, did not know it was supported.

Definitions says

signed integer type capable of holding a pointer to void

So is this a valid reinterpret_cast?

So is uint16_t.

It is, from https://en.cppreference.com/w/cpp/language/reinterpret_cast:

A pointer can be converted to any integral type large enough to hold all values of its type (e.g. to std::uintptr_t)

Or from the standard [expr.reinterpret.cast]:

  1. [Note 1 : The mapping performed by reinterpret_cast might, or might not, produce a representation different from
    the original value. — end note]
  2. A pointer can be explicitly converted to any integral type large enough to hold all values of its type. The mapping function is implementation-defined.
    [Note 2 : It is intended to be unsurprising to those who know the addressing structure of the underlying machine. — end note]
    A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type.
    [Note 3 : A reinterpret_cast cannot be used to convert a value of any type to the type std::nullptr_t. — end note]
  3. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
    [Note 4 : Except as described in 6.7.5.5.4, the result of such a conversion will not be a safely-derived pointer value. — end note]
1 Like

Thanks makes sense

I have executed your program of Post-12 on my UNO and the printed value for the pointer is 0x08FB which makes good sense as it is within the RAM space (0x0100 - 0x08FF).

Output:
8FB

So a better C++ version would be with

As PieterP pointed out.

That code @PieterP also works and gives the same pointer value of 0x08FB.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.