long long problem

General discussion on mikroC PRO for ARM.
Post Reply
Author
Message
orpheedulogis
Posts: 240
Joined: 16 Jan 2010 22:26

long long problem

#1 Post by orpheedulogis » 02 Jul 2015 17:48

Code: Select all

char FindAsciiHexaCodeValue(char CodeAscii)
{
   if ((CodeAscii<'0')||(CodeAscii<'A')) return 0;
   if (CodeAscii<='9') return CodeAscii-'0';
   if (CodeAscii<='F') return CodeAscii-'A'+10;
   return 0;
}



//----------------------------------------------------------------------------

unsigned int ConvertStringHexaToInt(char *StringH)
{
    char x1,y1;
    unsigned int Resultat=0;

    StringH=ltrim(StringH);
    for (x1=0;x1<strlen(StringH);x1++)
    {
        Resultat=(Resultat<<4)+ FindAsciiHexaCodeValue(StringH[x1]);
    }
    return Resultat;
}
This work but just for an integer


I need do do the same but for a "unsigned long long" variable and it doesn't works anymore !

Why ?

Also I found that just a single code like this one " unsigned long long Resultat=0;" doesn't work !

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: long long problem

#2 Post by aCkO » 03 Jul 2015 03:25

Yes, this is definitely a bug. It seems that the compiler has some problems in handling of 64-bit variables. I submitted a few bugs about this myself some time ago.

This is the problematic line:

Code: Select all

Resultat=(Resultat<<4)+ FindAsciiHexaCodeValue(StringH[x1]);
I tried with explicit typecast:

Code: Select all

Resultat=(Resultat<<4)+ (unsigned long long)FindAsciiHexaCodeValue(StringH[x1]);
but the compiler throws 'argument out of range' error at variable Resultat declaration/initialization. Making Resultat a global variable solves the problem, but that's obviously a bad solution.

Your function FindAsciiHexaCodeValue won't work correctly for decimal digits characters:

Code: Select all

char FindAsciiHexaCodeValue(char CodeAscii)
{
   if ((CodeAscii<'0')||(CodeAscii<'A')) return 0;
   ...
Characters '0' to '9' are < 'A' so the function will return 0.

To perform hex to long long conversion you can use the code below:

Code: Select all

char HexDigit(char c) {
   c.B5 = 1;   // convert to lowercase
   
   if (c >= '0' && c <= '9')
      return c - '0';
   else if (c >= 'a' && c <= 'f')
      return 10 + c - 'a';
   else
      return 0;
}

unsigned long long HexToLongLong(char *hex) {
   unsigned long long result = 0;
   char *p = (char *)&result;
   int i = 0, len = strlen(hex);
   char low = 0;
   
   if (len--) {
      hex += len;
      
      while ((len-- >= 0) && (i < 8)) {
         if (low ^= 0x01)
            p[i] = HexDigit(*hex--);
         else
            p[i++] |= HexDigit(*hex--) << 4;
      }
   }
   
   return result;
}
Regards

orpheedulogis
Posts: 240
Joined: 16 Jan 2010 22:26

Re: long long problem

#3 Post by orpheedulogis » 03 Jul 2015 07:09

Thanks for your answer.
My code ('0' ...'9' and 'A' ... 'F') was working but I changed some lines so present the problem (en english too) and forgot to verify.

So, if I understand, I can use a global "unsigned long long' variable and it will work ? As I just need one variable like that, I can declare it in 'global'. I will try


Update:

I tried your code and it work . Many thanks ! Event if i don't understand your pointer use :oops:

I noticed something strange: on your code, if I declare "len" as "char", I have exactly the same (false) result I had with my code.

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: long long problem

#4 Post by filip » 03 Jul 2015 16:28

Hi,

We will investigate this matter and report back.

Regards,
Filip.

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: long long problem

#5 Post by aCkO » 03 Jul 2015 21:51

orpheedulogis wrote:I noticed something strange: on your code, if I declare "len" as "char", I have exactly the same (false) result I had with my code.
You can't declare len as char because then its value would never be negative and the while loop condition would become invalid.
orpheedulogis wrote:I tried your code and it work . Many thanks ! Event if i don't understand your pointer use :oops:
The function parses the string from right to left. It begins at the end of the string and writes byte by byte to long long variable (little-endian order). I used it in one of my projects where right-to-left parsing was needed so I just copy-pasted it here. Of course, you can do it from left to right, like in your example. The code is then similar to your original example:

Code: Select all

char HexDigit(char c) {
   c.B5 = 1;   // convert to lowercase
   
   if (c >= '0' && c <= '9')
      return c - '0';
   else if (c >= 'a' && c <= 'f')
      return 10 + c - 'a';
   else
      return 0;
}

unsigned long long HexToLongLong(char *hex) {
   unsigned long long result = 0;
   
   hex = Ltrim(hex);
   
   while (*hex) {
      result <<= 4;
      *(char *)&result |= HexDigit(*hex++);
   }
   
   return result;
}
As a workaround, here I avoided using problematic arithmetic and logical operations on 64-bit and 8-bit data types by casting to char pointer and writing the lowest byte.

Regards

orpheedulogis
Posts: 240
Joined: 16 Jan 2010 22:26

Re: long long problem

#6 Post by orpheedulogis » 04 Jul 2015 08:22

aCkO wrote:
orpheedulogis wrote:I noticed something strange: on your code, if I declare "len" as "char", I have exactly the same (false) result I had with my code.
You can't declare len as char because then its value would never be negative and the while loop condition would become invalid.
orpheedulogis wrote:I tried your code and it work . Many thanks ! Event if i don't understand your pointer use :oops:
The function parses the string from right to left. It begins at the end of the string and writes byte by byte to long long variable (little-endian order). I used it in one of my projects where right-to-left parsing was needed so I just copy-pasted it here. Of course, you can do it from left to right, like in your example. The code is then similar to your original example:

Code: Select all

char HexDigit(char c) {
   c.B5 = 1;   // convert to lowercase
   
   if (c >= '0' && c <= '9')
      return c - '0';
   else if (c >= 'a' && c <= 'f')
      return 10 + c - 'a';
   else
      return 0;
}

unsigned long long HexToLongLong(char *hex) {
   unsigned long long result = 0;
   
   hex = Ltrim(hex);
   
   while (*hex) {
      result <<= 4;
      *(char *)&result |= HexDigit(*hex++);
   }
   
   return result;
}
As a workaround, here I avoided using problematic arithmetic and logical operations on 64-bit and 8-bit data types by casting to char pointer and writing the lowest byte.

Regards

Thanks a lot for your explanations.
For len, I was not using same code and didn't realised you where using "-1" case .

For pointer, for exampel, I didn't understand (and use) your pointer use :
you wrote "While (*hex)" but, in loop, you wrote "(*hex++)" so, for me, your "while(*hex)" is the same as "while(1)". Of course it's not ... but why ? :roll:
As I'm an autodidact, pointers use is not very easy for me.

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: long long problem

#7 Post by aCkO » 04 Jul 2015 14:06

orpheedulogis wrote:you wrote "While (*hex)" but, in loop, you wrote "(*hex++)" so, for me, your "while(*hex)" is the same as "while(1)". Of course it's not ... but why ? :roll:
As I'm an autodidact, pointers use is not very easy for me.
Pointers are no more complex than "regular" variables. Before entering the while loop hex points to the beginning of the string. Expression while (*hex) means "while character pointed by hex is not zero". To avoid having an infinite loop, inside the loop we must increment the pointer. Since hex initially points to the beginning of the string, by incrementing it we will eventually hit the terminator (zero) and exit while loop. It seems that the following expression is confusing you:

Code: Select all

HexDigit(*hex++);
This is equivalent to:

Code: Select all

HexDigit(*hex);
hex++;
As an example, let's write our version of strlen function:

Code: Select all

int MyStrLen(char *txt) {
   int len = 0;
   
   while (*txt) {
      txt++;
      len++;
   }
   return len;
}
or more compact:

Code: Select all

int MyStrLen(char *txt) {
   int len = 0;
   
   while (*txt++)
      len++;

   return len;
}
or if you prefer C-guru style:

Code: Select all

int MyStrLen (char *txt) {
   int len;
   for (len = 0; *txt++; len++);
   return len;
}
I hope this clarifies things a bit.

Regards

orpheedulogis
Posts: 240
Joined: 16 Jan 2010 22:26

Re: long long problem

#8 Post by orpheedulogis » 04 Jul 2015 14:26

Thanks a lot

When you use pointer, I traduce by variable witch is an adress. So, for me, "while (*pointer++)" is like "while (adress++)". That's why I don't expected adress would give a zero value !
But, as I see here, while (*pointer++) means you search at the pointer adress the corresponding data so, of course, you will have a zero at the end.

I suppose this is because I mix "&adress" and "*pointer"

Thanks again

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: long long problem

#9 Post by aCkO » 04 Jul 2015 15:04

I suspect that your confusion comes from pointer declaration statements. Address-of operator (&) returns a pointer to an existing object. The asterisk operator (*) in the declaration denotes a pointer, but in all other expressions it returns a pointed object. This is called dereferenced pointer.

Here's an example that should help:

Code: Select all

char c = 'A';  // c is char
char *p;       // p is a pointer to char
char tmp;

p = &c;        // p now points to c
               // p is the address of c
               // *p is the content at that address ('A')

tmp = *p++;    // tmp gets the value of pointed object ('A') and after that p is incremented (it points to new memory location: address = address + 1)
Think of pointers as regular integer variables that contain addresses of objects. Using the asterisk operator (*) you can indirectly access those objects.

Regards

orpheedulogis
Posts: 240
Joined: 16 Jan 2010 22:26

Re: long long problem

#10 Post by orpheedulogis » 04 Jul 2015 16:29

aCkO wrote:I suspect that your confusion comes from pointer declaration statements. Address-of operator (&) returns a pointer to an existing object. The asterisk operator (*) in the declaration denotes a pointer, but in all other expressions it returns a pointed object. This is called dereferenced pointer.

Here's an example that should help:

Code: Select all

char c = 'A';  // c is char
char *p;       // p is a pointer to char
char tmp;

p = &c;        // p now points to c
               // p is the address of c
               // *p is the content at that address ('A')

tmp = *p++;    // tmp gets the value of pointed object ('A') and after that p is incremented (it points to new memory location: address = address + 1)
Think of pointers as regular integer variables that contain addresses of objects. Using the asterisk operator (*) you can indirectly access those objects.

Regards
Yes, it's exactly the problem I had for understanding. Thanks

Just one question more:

Since "p" is an adress, "char" limit the adress to 0...255 but if you have many datas you must use "unsigned int" instead of "char", no ?

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: long long problem

#11 Post by aCkO » 04 Jul 2015 17:44

orpheedulogis wrote:Since "p" is an adress, "char" limit the adress to 0...255 but if you have many datas you must use "unsigned int" instead of "char", no ?
No.

If you add this line to my previous example:

Code: Select all

tmp = sizeof(p);
you will see that pointer size is 4. That means you can address a maximum 4GB of memory (addresses from 0 to 2^32-1). As I have said, pointers are just plain integers that store addresses and addresses don't have types. Data type used in pointer declaration is the type of pointed object. This is necessary in order for pointer arithmetic to work correctly. If you write:

Code: Select all

p++;
that doesn't mean address = address + 1 (well, it does if p is pointer to char). In general, when you write: p = p + n, that gets translated to: address = address + n * sizeof(T), where T is the type of pointed object. Here's an example:

Code: Select all

char *p1 = 120;   // p1 points to memory address 120 (randomly chosen)
int  *p2 = 120;   // p2 points to the same memory address as p1
long *p3 = 120;   // p3 points to the same memory address as p1 and p2

p1++;             // p1 = 120 + sizeof(char) = 120 + 1 = 121
p2++;             // p2 = 120 + sizeof(int)  = 120 + 2 = 122
p3++;             // p2 = 120 + sizeof(long) = 120 + 4 = 124
That's the reason why most people say pointers and arrays are equivalent in C although that is not quite true. Pointer arithmetic and array indexing are equivalent, arrays and pointers are not.

Regards

Post Reply

Return to “mikroC PRO for ARM General”