Why is arithmetic operation not working on pointer variable in UNOR3?


Figure-1:

Being inspired by a post in this Forum, I have explored a bit to understand the behavior of pointer variable referring to Fig-1. Unfortunately, my following sketch does not work to produce the expected result when ptr = &data2; code is replaced by ptr--;

void setup()
{
  Serial.begin(9600);
  int data1 = 0x1234; //data are saved in decreasing RAM memory locations
  int data2 = 0xABCD;
  int *ptr; //pointer variable ptr holds address of a word-wide location

  ptr = &data1; //ptr holds address of data1
  Serial.println((unsigned int)ptr, HEX); //shows: address of data1: 08FA
  int rdData1 = *ptr;
  Serial.println((unsigned int)rdData1, HEX);  //shows: 1234
  Serial.println();

  ptr--;//ptr = &data2; //ptr holds address of data2
  Serial.println((unsigned int)ptr, HEX); //shows:address of data2: 08F8
  int rdData2 = *ptr;
  Serial.println((unsigned int)rdData2, HEX);  //does not show: ABCD
  Serial.println();
}

void loop()
{

}

Output:

8FA
1234

8F8
F002

how do you know how the compiler/linker is allocating memory? from memory map?

if I run this

void setup() {
  Serial.begin(115200);
  delay(2000);
  int data1 = 0x1234;  //data are saved in decreasing RAM memory locations
  int data2 = 0xABCD;
  Serial.println((unsigned int)&data1, HEX);  //shows: address og data1
  Serial.println((unsigned int)&data2, HEX);  //shows: address of data2
  int *ptr;                                     //pointer variable ptr holds address of a word-wide location
  ptr = &data1;                            //ptr holds address of data1
  Serial.println((unsigned int)ptr, HEX);  //shows: address of data1: 08FA
  int rdData1 = *ptr;
  Serial.println((unsigned int)rdData1, HEX);  //shows: 1234
  Serial.println();
  ptr++;                                   //ptr = &data2; //ptr holds address of data2
  Serial.println((unsigned int)ptr, HEX);  //shows:address of data2: 08F8
  int rdData2 = *ptr;
  Serial.println((unsigned int)rdData2, HEX);  //does not show: ABCD
  Serial.println();
}

void loop() {
}

on anESP32 I get

3FFB2248
3FFB224C
3FFB2248
1234

3FFB224C
ABCD

ATmega32P (the AVR) of UNOR3 is of little endianness; where, least significant byte is stored in the lowest-order memory location.

Your ESP32 based functional sketch does not say anyting why my skecth of post #1 is not working for Arduino UNOR3.

OK - trying this on a UNO (changed ptr++; to ptr--; )

void setup() {
  Serial.begin(115200);
  delay(2000);
  int data1 = 0x1234;  //data are saved in decreasing RAM memory locations
  int data2 = 0xABCD;
  Serial.println((unsigned int)&data1, HEX);  //shows: address og data1
  Serial.println((unsigned int)&data2, HEX);  //shows: address of data2
  int *ptr;                                     //pointer variable ptr holds address of a word-wide location
  ptr = &data1;                            //ptr holds address of data1
  Serial.println((unsigned int)ptr, HEX);  //shows: address of data1: 08FA
  int rdData1 = *ptr;
  Serial.println((unsigned int)rdData1, HEX);  //shows: 1234
  Serial.println();
  ptr--;                                   //ptr = &data2; //ptr holds address of data2
  Serial.println((unsigned int)ptr, HEX);  //shows:address of data2: 08F8
  int rdData2 = *ptr;
  Serial.println((unsigned int)rdData2, HEX);  //does not show: ABCD
  Serial.println();
}

void loop() {
}

I get

8FA
8F8
8FA
1234

8F8
ABCD

is that what you expect?

If my memory map of Fig-1 of post #1 is correct, then the sketch should be working; but, it is not working. What is wrong with my memory map?

Your assumption about the order in which the compiler/linker assigned variable addresses.

I have not assumed the addresses; rather, I have shown the addresses from the Serial.print().

where you define a pointer, e.g.

the compiler knows the number of bytes allocated to an int (2 in the case of a UNO, 4 in the case of a ESP32)
therefore

ptr--;  

decrements ptr by 2 in the case of a UNO and 4 into case of a ESP32 - otherwise pointer arithmetic would not work

did yo intend to use a pointer to byte

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println(sizeof(int));
  int data1 = 0x1234;  //data are saved in decreasing RAM memory locations
  int data2 = 0xABCD;
  Serial.println((unsigned int)&data1, HEX);  //shows: address og data1
  Serial.println((unsigned int)&data2, HEX);  //shows: address of data2
  byte *ptr;                                     //pointer variable ptr holds address of a word-wide location
  ptr = (byte *) &data1;                            //ptr holds address of data1
  Serial.println((unsigned int)ptr, HEX);  //shows: address of data1: 08FA
  int rdData1 = *ptr;
  Serial.println((unsigned int)rdData1, HEX);  //shows: 1234
  Serial.println();
  ptr--;                                   //ptr = &data2; //ptr holds address of data2
  Serial.println((unsigned int)ptr, HEX);  //shows:address of data2: 08F8
  int rdData2 = *ptr;
  Serial.println((unsigned int)rdData2, HEX);  //does not show: ABCD
  Serial.println();
}

void loop() {
}

gives (on a UNO)

2
8FA
8F8
8FA
34

8F9
AB

You cannot assume any particular order for two separate variables, unless you have very deep knowledge of the exact allocation methods used in the compiler/linker.

If you had made an array of int, then you could use increment/decrement, or any other valid arithmetic, for a pointer within the array, but not to any variable declared separately.

Whether the processor is little or big endian is not relevant to the order in which two separate variables are stored.

If the following two lines of your sketch are commented out, then your sketch of post #4 works in UNOR3; otherwise, NOT.

//Serial.println((unsigned int)&data1, HEX);  //shows: address og data1
//Serial.println((unsigned int)&data2, HEX);  //shows: address of data2

think you're losing something when the signed int gets type cast to unsigned..
lose the last (unsigned int) on rData2..

good luck.. ~q

The originally posted code (with the line ptr--;) does in fact give the result that you expected, when compiled and run on a Pro Mini. But you should not make any assumptions about the order in which independent variables are stored in memory.

Printed results:

8FA
8F8
8FA
1234

8F8
ABCD


maybe it's a Wokwi thing??

Project simmed..

~q

again - as @jremington stated
"you should not make any assumptions about the order in which independent variables are stored in memory."

EDIT: a modern compiler/linker may not even store variables in memory but optimize the code to use processor registers

The placement of the variables is going to be dependent on the compiler used, which verison of the compiler is being used, the various optimizations used, the linker, as well as the processor that sketch is running on. If you intentionally declared a 16-bit integer on an ESP32 it could be aligned on a 32-bit boundary and completely throw off the increment/decrement, since there would be unused space between the variables.

Assuming any relative positioning between two separately declared variables definitely falls under "undefined behavior".

That means that the memory map of Fig-1 of post #1 is NOT authentic anyway to place data in the memory locations the way it has been shown.

Declaring an array like int myData = {0xABCD, 0x1234}; is, for sure, going to place the data1 and data2 in adjacent memory locations. This will make my sketch working with
ptr-- and yes, it works.
Output:

8FA
1234

8F8
ABCD

Now, the memory map and arithmetic operation on pointer variable are valid when the data items are guaranteed to be in adjacent memory locations.

In my case, the run-time variables show that the data have been stored in RAM locations.

Since I can't reproduce the original claim in the OP, can you explain why you stated that the sketch did not work?

This is the output of the original sketch of post #1; where, the memory map shows that the data are in adjacent memory locations. As I have understood from various posts of the thread that seperately declared data items might be placed at different locations during run-time.

8FA
1234

8F8
F002

post #15 @david_2018 has said that an array will ensure the placement of data items in adjacent memory locations. Based on this statement I have said that my sketch is going to work.

So, the memory map was incorrect.