Thread: Converting from 2's complement to decimal integer

  1. #1
    Registered User
    Join Date
    Dec 2001
    Posts
    40

    Converting from 2's complement to decimal integer

    Hi,
    I am converting data from an asn1 stream but my problem is with converting integer values. Asn1 works on a Tag, Length, Value (TLV) notation, so an integer can be stored in a variable length field. When that length is 1, 2 or 4 the conversion to a decimal value is relatively straight forward I am just doing this:

    Code:
        ber_tlv_tag_t TagSize;
        ber_tlv_tag_t TagValue;
        signed short ssTempInt = 0;
        signed int   siTempInt = 0;
    
    
               switch (TagSize)
               {
                   case 1:  TagValue =  *(const uint8_t *)&InputBuffer[CharsUsed];
                            ThisEvent->DataVolumeGprsUplink = (int) TagValue;
                            break;
                   case 2:  ssTempInt =  *(const uint16_t *)&InputBuffer[CharsUsed];
                            ThisEvent->DataVolumeGprsUplink = (int) ssTempInt;
                            break;
                   case 4:  siTempInt =  *(const uint32_t *)&InputBuffer[CharsUsed];
                            ThisEvent->DataVolumeGprsUplink = (int) siTempInt;
                            break;
                   default: TRACE(("Tagsize is not easily converted\0"));
                }
    Basically casting it to the appropriately sized variable. However when the variable is not of a standard size eg 3 bytes I am not entirely sure what to do? Should I do a 2's complement conversion to a decimal integer? Thoughts, ideas, suggestions appreciated?
    Thanks

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Since these are already in a char array, why not use:

    Code:
    union num {
    	int val;
    	char data[4];
    };
    Now pretend that "input" is your data, 4 24-bit numbers in row:

    Code:
    int main(void) {
    	char input[12] = "hello world";
    	int i, j;
    	union num eg;
    
    	for (i = 0; i < 4; i++) {
    		eg.val = 0;    // zero out the union
    		for (j = 0; j < 3; j++) eg.data[j] = input[j+i*3];
    		printf("%d\n",eg.val);
    	}
    
    	return 0;
    }
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    It call comes down to defining what a set of TagSize bytes represents for each value of TagSize.

    I assume that

    1) InputBuffer is an array of unsigned char.
    2) ThisEvent->DataVolumeGprsUplink is of a type that can hold any integral value represented by TagSize unsigned chars.

    Then I would probably do something like
    Code:
    ThisEvent->DataVolumeGprsUplink = 0;
    for (i = 0; i < TagSize; ++i)
    {
          ThisEvent->DataVolumeGprsUplink *= UCHAR_MAX;   /*  UCHAR_MAX is maximum value of unsigned char from <limits.h>
          ThisEvent->DataVolumeGprsUplink += InputBuffer[CharsUsed + i];
    }
    This assumes the byte order is most significant first. If first byte is least significant, reverse the order through the loop. If you have some other byte order corresponding to values, you will need to accommodate that in some other way.

    Incidentally, your approach can fail if int a type that is no bigger than 32 bits (which is common in practice) or short is less than 32 bits (which is very common in practice) . That is one reason why I would avoid using anything like your switch statement.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  4. #4
    Registered User
    Join Date
    Dec 2001
    Posts
    40
    Grumpy,
    I see what you are doing, its effectively in decimal terms, reading the first three digits and then multiplying by 1000 before getting the next three digits. There is probably a more technically correct way of putting that, but thats how I can visualise it in my head in a way that makes sense. The only thing I found was that on my box UCHAR_MAX is set to 255, which is the wrong value it needs to be 256 to work properly.
    Thanks for your help

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    UCHAR_MAX is set to 255, which is the wrong value it needs to be 256 to work properly
    Well since a char is 8 bits, the largest value it can hold is 255. Not sure what you think you can do about that.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Clancy's point - correctly - was that the value I needed to multiply by was UCHAR_MAX + 1 (the sample code I gave was off by 1).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. integer to two's complement
    By -EquinoX- in forum C++ Programming
    Replies: 8
    Last Post: 11-30-2009, 11:39 AM
  2. Replies: 5
    Last Post: 06-12-2007, 02:18 PM
  3. Integer and decimal
    By Bitojis in forum C++ Programming
    Replies: 3
    Last Post: 06-21-2005, 05:25 AM
  4. Converting decimal to hex
    By cobrakidd in forum C++ Programming
    Replies: 9
    Last Post: 02-06-2003, 11:37 AM