Solved

Convert input string in Little-endian

Posted on 2001-07-05
19
799 Views
Last Modified: 2010-08-05
Hello,
  I need to convert a string value to 4-byte BCD representation, in little-endian format.  How do I do that?
0
Comment
Question by:fareezaa
  • 8
  • 7
  • 3
  • +1
19 Comments
 
LVL 6

Expert Comment

by:zebada
Comment Utility
Not sure how you mean to encode BCD as "little endian"
My guess is you want to see the string 12345678
stored as HEX: 87 65 43 21

This code should do that for you

#include <stdio.h>
#include <string.h>

typedef unsigned char BYTE;

int main(int argc, char *argv[])
{
  char *c,*s = "45678";
  BYTE *b,bcd[4];
  int i;

  for ( b=bcd,i=0 ; i<4 ; i++ )
    *b++ = 0;
  b = bcd;
  for ( c=s+strlen(s)-1 ; s<=c ; c-=2 ) {
    *b = (*c-'0') << 4;
    if ( s<c )
      *b |= (*(c-1)-'0');
    b++;
  }

  for ( i=0 ; i<4 ; i++ )
    printf("%2.2x,",bcd[i]);
}
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> My guess is you want to see the string 12345678
>> stored as HEX: 87 65 43 21
That is big endian.
87 65 43 21

is little endian.

You can just reverse the final product.
0
 
LVL 6

Expert Comment

by:zebada
Comment Utility
neitod, huh?
Isn't little endian the LSB first?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Opps, I didn't reverse it!

Little endian means that the little part, the least significant part, appears at the end, at the highest address.  So a number like

12345678

would be stored as 4 bytes from low to high addresses that contain

0x12 0x34 0x56 0x78

0
 
LVL 6

Expert Comment

by:zebada
Comment Utility
bummer!!!!

I guess that's why I always refer to "MSB first" or "LSB first". Never knew what "endian" meant - from your explanation I guess it means "end".
0
 

Author Comment

by:fareezaa
Comment Utility
ok.
but i need to prompt the user for the value.  From the example you showed, both pointers value has been been initialized with values.  Using that it works, but when i modify the code to get user input,  It gives me error.  This is the snippet of the code:
--
char *c, *s;
BYTE *b,bcd[4];
int i=0;

printf("\n\nPlease enter your PIN to log in or 'q' to quit:\n");
scanf("%s", &c);
printf("%s",&c);
--

how can i copy these value to s as well? or get this code to be working?
0
 

Author Comment

by:fareezaa
Comment Utility
and i forgot to include that the char *c, *s needs to be as unsigned char s[].
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
You are using scanf() incorrecly.  When you read a string wiht scanf() you need to pass a pointer to an array of characters that will receive the result. Like

char c[100]; // Array to store a string of up to 99 characters.

scanf("%s", c);


However, it is a bad idea to be using C I/O in C++ programs.  As you can tell, it is easy to use it correctly adn make mistakes that cause crashes or other problems.

Instead use C++ i/O like


char c[100];

cin >> c;


Or better yet, use string objects like

string c;

cin >> string.
0
 

Author Comment

by:fareezaa
Comment Utility
Hello,
 when i do it that way, i still get errors. the errors are:
1. error C2440: '=' : cannot convert from 'char *' to 'char [30]'.  There are no conversions to array types, although there are conversions to references or pointers to arrays
2. error C2106: '-=' : left operand must be l-value.

the code:

int main(int argc, char *argv[])
{
char *s ;
BYTE *b,bcd[4];
int i=0;
char c[30];

printf("\n\nPlease enter your PIN to log in or 'q' to quit:\n");
cin>>c;
s = c;  //i need to copy value of c to s

for ( b=bcd,i=0 ; i<4 ; i++ )
*b++ = 0;
b = bcd;
for ( c=s+strlen(s)-1 ; s<=c ; c-=2 ) {                        <- error 1 and 2
     *b = (*c-'0') << 4;
      if ( s<c )
     *b |= (*(c-1)-'0');
      b++;
}

for ( i=0 ; i<4 ; i++ )
printf("%2.2x ",bcd[i]);
}
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 84

Expert Comment

by:ozo
Comment Utility
for ( s=c+strlen(c)-1 ; c<=s ; s-=2 ) {  
    *b = (*s-'0') << 4;
     if ( c<s )
    *b |= (*(s-1)-'0');
     b++;
}
0
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
Comment Utility
>> 1. error C2440: '=' : cannot convert from 'char *' to 'char [30]'.  There are
>> no conversions to array types, although there are conversions to references
>> or pointers to arrays
You cannot copy NUl terminated strings with =.   You must use strcpy() or you must use a C++ string object that supports operator =.   (using string objects is definitely prefered!)

>> 2. error C2106: '-=' : left operand must be l-value.
You are trying to subtract 2 from "c".  That worked when c was a pointer.  It made "c" point to the character that was 2 characters before where it was pointing before.   But you made "C" into an array.  You can't do that with an array.  



Here is the code that I use to pach data.  Note that it handles hexx values too (values outside of the digit range (0-9))  So for example  "AB"  is packed to a byte that stores OxAB.  Note also that if the number of source bytes is odd, the high nibble of the result is made 0.  so "123" is packed to 0x01,0x23

typedef unsigned char uByt;

// TITLE:  Convert ASCII Hex Digit to Binary                                                      //
//      This procedure converts a byte containing an ASCII character representing a Hex digit to  //
// the binary value it represents.                                                                //
uByt
Hex2Bin(uByt h)
{
   if ('0' <= h && h <= '9')                     // If this is a decimal digit, then              //
      return ((uByt)(h-'0'));                    // convert to binary.                            //
   else if ('a' <= h && h <= 'f')                // If this is a lowercase hex digit letter,      //
      return ((uByt)(h-'a'+10));                 // convert to binary.                            //
   else if ('A' <= h && h <= 'F')                // If this is a uppercase hex digit letter,      //
      return ((uByt)(h-'A'+10));                 // convert to binary.                            //
   return 0;
}
// TITLE:  Pack ASCII Data                                                                        //
//      This procedure packs an array of ASCII characters to an array of packed bytes.  That is,  //
// the value in each byte of the source array is packed into a nibble of a byte in the            //
// destination array.  Since each pair of bytes in the source array is packed into one byte of    //
// the destination, the destination array must only be half the length of the source array.       //
// Hence the term packing.  Thus, the 4 byte array "1234" would be converted to the 2 byte array  //
// 0x12,0x34.                                                                                     //
//                                                                                                //
//      Each of the bytes in the source array must contain an ASCII digit ("0"-"9") or an         //
// uppercase or lowercase letter from "A" to "F".                                                 //
//                                                                                                //
//      The length specified is the number of unpacked bytes to be packed.  If this value is      //
// even, then the number of bytes in the destination array must be half of this value and each    //
// nibble in the destination will be packed from a byte in the source.  If this value is odd, the //
// destination array must be half this value rounded up and the high nibble of the first byte     //
// will be set to zero and the low nibble will be set from the first byte of the source.  Thus    //
// packing the 3 byte array "678" into a 2 byte array would yield 0x06,0x78.                      //
void
QMthPckASC(void       *Dst,                      // -> destination buffer.  Must be at least half //
                                                 // the number of bytes (rounded up) specified by //
                                                 // the Cnt parameter.                            //
           const void *Src,                      // -> source buffer.  Must be at least the size  //
                                                 // specified by the Cnt parameter.               //
           size_t      Cnt)                      // Number of unpacked bytes to pack.  If odd the //
                                                 // high nibble of the first byte will be zeroed. //
                                                 // May be zero.                                  //
{
   uByt *D = (uByt *) Dst;                       // -> destination bytes.                         //
   uByt *S = (uByt *) Src;                       // -> source bytes.                              //
   uByt  u;                                      // Generic value.                                //
   uByt  v;                                      // Generic value.                                //

   if (Cnt & 1)                                  // If count is odd, then                         //
   {
      u = *S++;                                  // Get source byte.                              //
      *D++ = Hex2Bin(u);                         // Set low nibble of destination byte.           //
      --Cnt;                                     // Decrement the count.                          //
   }
   while (Cnt)                                   // While there are more destination bytes.       //
   {
      u = *S++;                                  // Get source byte.                              //
      v = *S++;                                  // Get source byte.                              //
      *D++ =  (uByt)(Hex2Bin(u) << 4) | Hex2Bin(v); // Set destination byte.                      //
      Cnt -= 2;                                  // Decrement the count.                          //
   }
}
0
 

Author Comment

by:fareezaa
Comment Utility
how to i print out the return value of Hex2Bin(uByt h) function?

i did this:
char c[30];
     
printf("\n\nPlease enter your PIN to log in or 'q' to quit:\n");
cin >> c;
     
printf("\nthe result is: \"%s\"\n", c);
s = c;
cout<<"\ns value: "<<s;

BYTE x = Hex2Bin(*c);
cout<<"\nx value: "<<x;
--
and i get weird output..a symbol of a smiling face.

0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> and i get weird output..a symbol of a smiling face.
That would be very likely.  Its a byte containing a packed BCD value.  its not necessarily going to be a valid ASCII character.

You can convert it to a number (int) then print the int.

cout << (int) Hex2Bin(*c);
0
 

Author Comment

by:fareezaa
Comment Utility
hello,
when i convert [the cout << (int) Hex2Bin(*c)],the answer is 1.  that is not what i am looking for.  
When the user input :12345678,
the answer shud be {{0x87}, {0x65}, {0x43}, {0x21}}; but i don't know how to get this.
I've tried zebada's way but it's the other way around (87 65 43 21) and it is not working.
:(
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
hex2Bin is not meant to do that conversion.  Read the comments about it It converts a single ASCII digit/letter to a  byte that contains the binary value represened by the ASCII value.  I.e. it converts the digit "1" to binary 1.  It converts "A" to binary 10 (0xA)  it converts "b" to 11 and so on.

The procedure is used by QMthPckASC()  That procedure  packs one string of ASCII digits/letters to a string of binary BCD bytes.

Read the commens on it.  it explains what it does and what each parameter is.
0
 

Author Comment

by:fareezaa
Comment Utility
when i use that way, it will return me 0x87 0x65 0x43 0x21.  the expected result is 0x78 0x56 0x34 0x12.   so i change some of the code and it works. But what if the input is odd, say 12345.  Should it be
a-(0x54 0x32 0x01)
 or
b- (0x05 0x43 0x21)?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>>  it will return me 0x87 0x65 0x43 0x21
If you feed it a string that is (from low to high address) "12345678" it will return to you a string that is (from low to high)
0x12, 0x34, ix56, 0x78.

>> Should it be
What do you want?  It should be what you need according to your needs.
0
 

Author Comment

by:fareezaa
Comment Utility
THANKS.  i think it shud be b+, not b
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
You could have rounded it up to an A.  :-)
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now