Go Down

Topic: uint32_t weirdness (Read 3972 times) previous topic - next topic

chucktodd

Arduino 1.6.5 - MEGA2560

I have a simple routine to convert a Hexadecimal string to a uint32_t value, but it is not generating the expected value.  Here is the code, and a debug Serial stream.

Code: [Select]

uint32_t htoli(const char inbuf[]){
uint32_t b=0;
uint16_t a;
uint8_t c;
Serial.print("htoli(\"");
Serial.print(inbuf);
Serial.print("\")=\n");
bool err=false;
while((c=inbuf[a++])&&!err){
c = toupper(c);
Serial.print(" c(chr)=");
Serial.print((char)c);
if(((c>='0')&&(c<='9'))||((c>='A')&&(c<='F'))){
Serial.print(" b=");
Serial.print(b,DEC);
Serial.print(" ");
b=b*16;
Serial.print(" after mul b=");
Serial.print(b,DEC);
Serial.print(" c(dec)=");
  c= c-48;
if(c>9)c=c-7;
b = b + c;
Serial.print(c,DEC);
Serial.print(", after add (b=b+c) b=");
Serial.print(b,DEC);
Serial.print("\n");
}
else {
Serial.print("error? ");
err=true;
}
}
//if(err) b=0;
Serial.print("result =");
Serial.println(b,DEC);
return b;
}
 


Here is the Debug out:

htoli("800")=
 c(chr)=8 b=0  after mul b=0 c(dec)=8, after add (b=b+c) b=8
 c(chr)=0 b=0  after mul b=0 c(dec)=0, after add (b=b+c) b=0
 c(chr)=0 b=0  after mul b=0 c(dec)=0, after add (b=b+c) b=0
result =0



Can anyone tell me why I can't find the problem?

Somewhere between the first and second iteration of the while(), the value of b is reset to Zero?

Chuck.
Currently built mega http server, Now converting it to ESP32.

el_supremo

What is the initial value of 'a' ?

Pete
Don't send me technical questions via Private Message.

jremington


chucktodd

What is the initial value of 'a' ?

Pete
I agree that it should be initialized, but based on the values of 'c' it is init'd to 0.

Can you see any reason that 'b' would be reset to zero?

Chuck.
Currently built mega http server, Now converting it to ESP32.

chucktodd

Why not use strtol()?
It might be easier, but I want to know why this code fails.  If this simple coding is generating incorrect machine code I want to Know.  

If there is some known uint32_t interaction faults, I would like to know them.

I am in the middle of a WebServer project that uses a Mega, with EEPROM, SPI Flash, SPI Ram, and SDcards for storage.

This code that exploded was called by my EEProm format routine, I have constructed a simple FAT file system, and a web server with SSI functionality.  I plan on using it to capture sensor data from other Arduino IOT devices,  Something like SparkFun's Data service.  Something that can act as a repository for other devices.  

Currently I am able to upload and download files with CURL.exe and of course Web browser access,  I was working on the POST multipart/form-data format when this error cropped up.  I want to squash it, at least understand what is going wrong so that I can defensively code around problem.

Chuck.  
Currently built mega http server, Now converting it to ESP32.

el_supremo

Quote
I agree that it should be initialized,
Definitely.

Quote
but based on the values of 'c' it is init'd to 0.
That's not a comforting thought. A bug is a bug. Fix it, and then if there are still problems you will know that at least the initial value of 'a' is not causing any of them.

Based on my quick test, not initializing 'a' is the problem.

Pete
Don't send me technical questions via Private Message.

chucktodd

#6
Sep 08, 2016, 01:38 am Last Edit: Sep 08, 2016, 01:40 am by chucktodd Reason: theamatic
Definitely.
That's not a comforting thought. A bug is a bug. Fix it, and then if there are still problems you will know that at least the initial value of 'a' is not causing any of them.

Based on my quick test, not initializing 'a' is the problem.

Pete
Pete, you are correct, Initializing 'a' does 'solve' the problem, but how did initializing 'a' change the code generated generated in the while() loop?


htoli("800")=
 c(chr)=8 b=0  after mul b=0 c(dec)=8, after add (b=b+c) b=8
 c(chr)=0 b=8  after mul b=128 c(dec)=0, after add (b=b+c) b=128
 c(chr)=0 b=128  after mul b=2048 c(dec)=0, after add (b=b+c) b=2048
result =2048


Chuck.

p.s. still lost in the Dark!
Currently built mega http server, Now converting it to ESP32.

jremington

Quote
If this simple coding is generating incorrect machine code
Extremely unlikely. There are millions of people who use avr-gcc every day and genuine compiler bugs are few, far between and difficult to discover.

Delta_G

Pete, you are correct, Initializing 'a' does 'solve' the problem, but how did initializing 'a' change the code generated generated in the while() loop?

It didn't change the code generated.  a had some garbage value left over in it when it was created and not initialized.  Since it wasn't 0, it simply wasn't reading the bytes you thought it would. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

chucktodd

Extremely unlikely. There are millions of people who use avr-gcc every day and genuine compiler bugs are few, far between and difficult to discover.
Maybe not a fatal flaw, but it did produce unexpected results.

How could not initializing an index variable cause a different variable to change its value?  

I could see if the index variable was being used to change a memory structure, but the index variable was performing correctly, there was a side effect.

Chuck.
Currently built mega http server, Now converting it to ESP32.

Delta_G

How could not initializing an index variable cause a different variable to change its value? 

It doesn't.  You weren't reading where you thought you were.  Imagine that a started out with a 1 in it.  You'd never see the 8 and you'd parse the two 0's and get 0 as an answer.  You weren't reading in the "800".  You were probably reading somewhere off in who knows what part of memory.

To prove it, go back to your old code and print a so you can see what value it was getting.  Now go and use that value to initialize a and see that you get the exact same wrong result.  What if a was getting the initial value of 64?  What character was in inbuf[64]?  That's the character being parsed, not your "800"
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

chucktodd

It didn't change the code generated.  a had some garbage value left over in it when it was created and not initialized.  Since it wasn't 0, it simply wasn't reading the bytes you thought it would.  
No,
 as the debug output shown, the value of 'c' was changing in the expected manner.  First it was the character '8' then the character '0', then the character '0'.

Whatever value 'a' had, (I think it started at zero), it was indexing through the char[] correctly.  If it was pointed somewhere else,

htoli("800")=
c(chr)=8 b=0  after mul b=0 c(dec)=8, after add (b=b+c) b=8
c(chr)=0 b=0  after mul b=0 c(dec)=0, after add (b=b+c) b=0
c(chr)=0 b=0  after mul b=0 c(dec)=0, after add (b=b+c) b=0
result =0


the c(chr)= value would show something else.  Between the c(chr) and c(dec) the code subtracted 48 and conditionally another 7 if necessary.  

This exposes an edge condition, I want to know were the edge is before I place my feet. :)

Chuck.
Currently built mega http server, Now converting it to ESP32.

jremington

Agreed, the results are unexpected. The surprising thing is that when not initializing "a", it appears that the array is still indexed correctly, that is the correct character appears to be retrieved.

The unexpected behavior probably has to do with how the compiler optimizes the code with regard to initialized versus uninitialized indices.

When I suspect an optimization problem, I turn it off.  That is required anyway when debugging, because the compiler can put optimized code anywhere it "wants" as long as the end result is correct.

chucktodd

It doesn't.  You weren't reading where you thought you were.  Imagine that a started out with a 1 in it.  You'd never see the 8 and you'd parse the two 0's and get 0 as an answer.  You weren't reading in the "800".  You were probably reading somewhere off in who knows what part of memory.

To prove it, go back to your old code and print a so you can see what value it was getting.  Now go and use that value to initialize a and see that you get the exact same wrong result.  What if a was getting the initial value of 64?  What character was in inbuf[64]?  That's the character being parsed, not your "800"
Debug results with 'a' initialized:

htoli("64")=
 c(chr)=6 b=0  after mul b=0 c(dec)=6, after add (b=b+c) b=6
 c(chr)=4 b=6  after mul b=96 c(dec)=4, after add (b=b+c) b=100
result =100
returned value of htoli("64")=100
htoli("64")=
 c(chr)=6 b=0  after mul b=0 c(dec)=6, after add (b=b+c) b=6
 c(chr)=4 b=6  after mul b=96 c(dec)=4, after add (b=b+c) b=100
result =100
returned value of htoli("buf")=100


the calling code:
Code: [Select]

char buf[10];
uint32_t bigValue = htoli("64");
Serial.print("returned value of htoli(\"64\")=");
Serial.println(bigValue,DEC);
sprintf(buf,"64");
bigValue = htoli(buf);
Serial.print("returned value of htoli(\"buf\")=");
Serial.println(bigValue,DEC);


Debug output with the initialization code for 'a' removed:

htoli("64")=
 c(chr)=6 b=0  after mul b=0 c(dec)=6, after add (b=b+c) b=6
 c(chr)=4 b=0  after mul b=0 c(dec)=4, after add (b=b+c) b=4
result =0
returned value of htoli("64")=0
htoli("64")=
 c(chr)=6 b=0  after mul b=0 c(dec)=6, after add (b=b+c) b=6
 c(chr)=4 b=0  after mul b=0 c(dec)=4, after add (b=b+c) b=4
result =0
returned value of htoli("buf")=0


The code that produces this error:
Code: [Select]

uint32_t htoli(const char inbuf[]){
uint32_t b=0;
uint16_t a;
uint8_t c;
Serial.print("htoli(\"");
Serial.print(inbuf);
Serial.print("\")=\n");
bool err=false;
while((c=inbuf[a++])&&!err){
 c = toupper(c);
 Serial.print(" c(chr)=");
 Serial.print((char)c);

 if(((c>='0')&&(c<='9'))||((c>='A')&&(c<='F'))){
 Serial.print(" b=");
 Serial.print(b,DEC);
 Serial.print(" ");

 b=b*16;
 Serial.print(" after mul b=");
 Serial.print(b,DEC);
 Serial.print(" c(dec)=");

  c= c-48;
 if(c>9)c=c-7;
 b = b + c;
 Serial.print(c,DEC);
 Serial.print(", after add (b=b+c) b=");
 Serial.print(b,DEC);
 Serial.print("\n");

 }
 else {
 Serial.print("error? ");
 err=true;
 }
 }

Serial.print("result =");
Serial.println(b,DEC);

return b;
}



This is a reproducible error.  Something is wrong.

Chuck.
Currently built mega http server, Now converting it to ESP32.

Delta_G

Why not print a since that value seems to be the source of at least some part of the problem.
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Go Up