Debugging and internal organisation of global variables

Status
Not open for further replies.

cebersp

Well-known member
Hi,
some hints for 2 questions, please?
My multitrack looper project uses audio library and threads library, things are going on FAST.
Up to now I have used serial.print() for debugging in arduino.

A) Are there more advanced still easy ways available?

B) I am trying to print out global int variables, it only prints the first Variable "917", the rest is rubbish, what's wrong there?
I tried
*(&dummy + i*4)
too, but it did not get right results too. How is the organisation of global variables in memory?

Code:
int dummy=917;
int dummy2=918;
int maxBuf= 0;
uint maxRecLength= 44100*20; //44100*5; 3*sdBufLen;
uint actPos= 0;
uint posInBuf= 0;
int recTrack= 0;

int recBuf= 0; 
int readBuf= -1;
int writeBuf= -1;

int writePos= 0;
int readPos= 0;
int endFlag= 0;
int recStatus= 1; 

.....


void lsGlobals() {

  Serial.print("\nGlob: ");
  for(int i=0; i<10; i++) {
    Serial.printf(" %d", *(&dummy + i) );
  }
}

Thanks in advance!
Christof
 
The code is making assumptions about storage order - and also the syntax in the printf isn't telling the compiler to do what is hoped for.

Run this and notice the added print of the %p pointer address as it resolves in print for the various cases.

Code:
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

  lsGlobals();
}

void loop() {
  // put your main code here, to run repeatedly:

}

int dummy=917;
int dummy2=918;
int maxBuf= 0;
uint maxRecLength= 44100*20; //44100*5; 3*sdBufLen;
uint actPos= 0;
uint posInBuf= 0;
int recTrack= 0;

int recBuf= 0; 
int readBuf= -1;
int writeBuf= -1;

int writePos= 0;
int readPos= 0;
int endFlag= 0;
int recStatus= 1; 

uint32_t uiA[10] = {11,22,33,44,55,66,77,88,99,678};

void lsGlobals() {

  Serial.print("\nGlob: ");
  for(int i=0; i<10; i++) {
    Serial.printf(" %ld @ %p \n", *(&dummy + i), (&dummy + i) );
  }
  Serial.println();
  for(int i=0; i<10; i++) {
    Serial.printf(" %lu @ %p \n", *(&uiA + i), (&uiA + i) );
  }
  Serial.println();
  for(int i=0; i<10; i++) {
    Serial.printf(" %lu @ %p \n", uiA[i], (&uiA + i) );
  }
  Serial.println();
  for(int i=0; i<10; i++) {
    Serial.printf(" %lu @ %p \n", uiA[i], &uiA[i] );
  }
}

Here's t_4.1 output from that completed code:
Code:
C:\T_Drive\tCode\FORUM\RandomPrint\RandomPrint.ino Jan 23 2022 23:45:15

Glob:  917 @ 0x20000fe0 
[U] 11 @ 0x20000fe4 
 22 @ 0x20000fe8 
 33 @ 0x20000fec 
 44 @ 0x20000ff0 
 55 @ 0x20000ff4 
 66 @ 0x20000ff8 
 77 @ 0x20000ffc 
 88 @ 0x20001000 
 99 @ 0x20001004 [/U]

 536874980 @ 0x20000fe4 
 536875020 @ 0x2000100c 
 536875060 @ 0x20001034 
 536875100 @ 0x2000105c 
 536875140 @ 0x20001084 
 536875180 @ 0x200010ac 
 536875220 @ 0x200010d4 
 536875260 @ 0x200010fc 
 536875300 @ 0x20001124 
 536875340 @ 0x2000114c 

 11 @ 0x20000fe4 
 22 @ 0x2000100c 
 33 @ 0x20001034 
 44 @ 0x2000105c 
 55 @ 0x20001084 
 66 @ 0x200010ac 
 77 @ 0x200010d4 
 88 @ 0x200010fc 
 99 @ 0x20001124 
 678 @ 0x2000114c 

[B] 11 @ 0x20000fe4 
 22 @ 0x20000fe8 
 33 @ 0x20000fec 
 44 @ 0x20000ff0 
 55 @ 0x20000ff4 
 66 @ 0x20000ff8 
 77 @ 0x20000ffc 
 88 @ 0x20001000 
 99 @ 0x20001004 
 678 @ 0x20001008 [/B]
 
Thank you!
So you suggest to use one global array for the variables, to be sure of the memory location of those?
 
Thank you!
So you suggest to use one global array for the variables, to be sure of the memory location of those?

Yes, for a simple fast loop as posted that is a good solution - as long as all the vars can be the same type. Perhaps a second array and loop if int and uint are both needed.
 
you can also use a struct
then you can keep the variable names +access the items in a loop

after a lot of trial and error I found out that you can do it like this
Code:
struct IntVars {
  int fid=0; // first item dummy;
  int dummy=917;
  int dummy2=918;
  int maxBuf= 0;
  int recTrack= 0;
  int recBuf= 0; 
  int readBuf= -1;
  int writeBuf= -1;
  int writePos= 0;
  int readPos= 0;
  int endFlag= 0;
  int recStatus= 1;
  int lastItem=-42;
};
struct uIntVars{
  uint fid=0; // first item dummy;
  uint maxRecLength= 44100*20; //44100*5; 3*sdBufLen;
  uint actPos= 0;
  uint posInBuf= 0;
  uint lastItem=42;
};

IntVars iv;
uIntVars uiv;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  
  Serial.printf("sizeof iv %ld %ld\n", sizeof(iv), sizeof(int) );
  Serial.printf("sizeof iiv %ld %ld\n", sizeof(uiv),sizeof(uint) );

  //IntVars *_ivp = &iv;
  //_ivp++; // this actually increase the address with sizeof(iv)
  
  Serial.println("\ncontents of iv:");

  // note. (sizeof(iv)/sizeof(int)+&iv.fid) may look a little strange but it works

  for(int *ivp = &iv.fid+1; ivp<(sizeof(iv)/sizeof(int)+&iv.fid); ivp++) {
    Serial.printf(" %d @ %p\n", *ivp, ivp);
  }

  Serial.println("\ncontents of uiv:");
  for(int *uivp = &uiv.fid+1; uivp<(sizeof(uiv)/sizeof(uint)+&uiv.fid); uivp++) {
    Serial.printf(" %u @ %p\n", *uivp, uivp);
  }
}
 
Last edited:
you can also use a struct
then you can keep the variable names +access the items in a loop

after a lot of trial and error I found out that you can do it like this
Code:
struct IntVars {
  int fid=0; // first item dummy;
  int dummy=917;
  int dummy2=918;
  int maxBuf= 0;
  int recTrack= 0;
  int recBuf= 0; 
  int readBuf= -1;
  int writeBuf= -1;
  int writePos= 0;
  int readPos= 0;
  int endFlag= 0;
  int recStatus= 1;
  int lastItem=-42;
};
struct uIntVars{
  uint fid=0; // first item dummy;
  uint maxRecLength= 44100*20; //44100*5; 3*sdBufLen;
  uint actPos= 0;
  uint posInBuf= 0;
  uint lastItem=42;
};

IntVars iv;
uIntVars uiv;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  
  Serial.printf("sizeof iv %ld %ld\n", sizeof(iv), sizeof(int) );
  Serial.printf("sizeof iiv %ld %ld\n", sizeof(uiv),sizeof(uint) );

  //IntVars *_ivp = &iv;
  //_ivp++; // this actually increase the address with sizeof(iv)
  
  Serial.println("\ncontents of iv:");

  // note. (sizeof(iv)/sizeof(int)+&iv.fid) may look a little strange but it works

  for(int *ivp = &iv.fid+1; ivp<(sizeof(iv)/sizeof(int)+&iv.fid); ivp++) {
    Serial.printf(" %d @ %p\n", *ivp, ivp);
  }

  Serial.println("\ncontents of uiv:");
  for(int *uivp = &uiv.fid+1; uivp<(sizeof(uiv)/sizeof(uint)+&uiv.fid); uivp++) {
    Serial.printf(" %u @ %p\n", *uivp, uivp);
  }
}

Thanks, this is interesting!
I fortunately found my last bug, but others will come....
 
How is the organisation of global variables in memory?
In C and C++ this is undefined - the compiler and linker are both free to reorder/position things however they like,
whether static, global, local or whatever. Various optimizations may want to control placement for improved
performance (relative addressing, locality of reference, cache line alignment, etc etc).

Even if the compiler doesn't do this, a future upgrade might, so you cannot assume anything about memory placement
of distinct variables other than the alignment requirements of the architecture.

In some circumstances the compiler might optimize a global variable away completely if its static, not volatile and isn't live
between function calls, or its value can be determined unambiguously constant at compile-time (ie things that could have
been defined const or automatic). Compilers can be smart.
 
Status
Not open for further replies.
Back
Top