Thread: creating a variable consisting of two other variables side by side

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    22

    creating a variable consisting of two other variables side by side

    Code:
    #include <stdio.h>
    #include <string.h>
    
    main() {
           int TMR1H = 12345678;
           int TMR1L = 12345678;
           char str1[8];
           char str0[8];
           str1[0] = TMR1H;
           str0[0] = TMR1L;
           char str[16];
           strcpy (str, str1);
           strcat (str, str0);
           printf("%s", str);
           getchar();
    }

    This is my code so far. All I want is to create a variable which consists of TMR1H immediately followed by TMR1L. These two variables contain the first half(L) and second half(H) of a 16 bit binary number. I dont want any arithmetic operations performed on them, simply str = 1234567812345678. Ideally, the output type is an int. At the moment I'm getting some odd characters from the printf function. Im probably doing very silly things here so if anyone can enlighten me I would be very grateful!

    Dan

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Lots of things...

    1) The correct entry point for C programs is int main (void)
    2) Since main return an int you must return a value when exiting; typically 0.
    3) 12345678 is to big to fit in a 16 bit binary number... 65535 is the max for an unsigned value.
    4) You cannot assign integers to strings without conversion.
    5) str1[0] is an 8 bit value that cannot hold 12345678 and will cause an overflow.
    6) All your strings are too short , they need at least 1 extra space for the null teriminator.

    Overall I would also suggest your approach is wrong since this is very easily done with simple math.

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    Yep I thought I was. I've been at this for ages so everything is a littlr blurry, I knew half the stuff you just pointed out =/ I've rethought the whole thing - would this work:

    t1 = (TMR1H*256) + TMR1L

    given that TMR1H is the most significant 8 bits of a 16 bit binary number?

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by dannybeckett View Post
    Yep I thought I was. I've been at this for ages so everything is a littlr blurry, I knew half the stuff you just pointed out =/ I've rethought the whole thing - would this work:

    t1 = (TMR1H*256) + TMR1L

    given that TMR1H is the most significant 8 bits of a 16 bit binary number?
    Yep... it's about that simple BUT the values you are giving 12345678 will not fit in a 16 bit value...
    They will cause overflows, returning garbage answers.

    If you are combining 2 8 bit values you are restricted to numbers from 0 to 255. and t1 must be type int or short int.

    If you are combining 2 16 bit values to make a 32 you are restricted to 0 -> 65535 in each base value and t1 needs to be an int or long int the formula becomes:

    t1 = (tmr1h * 65536) + tmr1l;

    To do it with type safety you should use:

    t1 = ((tmr1h & 65535) * 65536) + (tmril & 65535)

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    Excellent, thanks a lot. I know that value wont fit into a 16 bit binary number, I was being rediculous choosing it in the first place. I believe 123456789 corresponds to 111010110111100110100010101 hahahaha.

    I understand everything you just told me apart from the last line.

    t1 = ((tmr1h & 65535) * 65536) + (tmril & 65535)

    Would you care to explain what's going on here?

    Thanks for your patience

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Basically, Tater showed you a way to move the 16 bits in tm1h to the "left" half of t1, and put the 16 bits from tmr1l into the "right" half of t1. He used multiplication by a power of 2 (65536 = 2^16) to shift some bits to the left, and addition to combine the two values. It could also be expressed this way:
    Code:
    t1 = ((tmr1h & 0xFFFF) << 16) | (tmr1l & 0xFFFF);
    If that's still not clear, you need to spend some time understanding the bitwise operators. We have some info on this site:
    Cprogramming.com FAQ > Bit shifting and bitwise operations
    Cprogramming.com - Tutorials - Bitwise Operators and Bit Manipulations in C and C++
    and of course, Google is always useful.

    EDIT: The & is to make sure you're working with at most two 16-bit pieces of info.
    Last edited by anduril462; 03-07-2011 at 06:13 PM. Reason: fixed error in code

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by dannybeckett View Post
    Excellent, thanks a lot. I know that value wont fit into a 16 bit binary number, I was being rediculous choosing it in the first place. I believe 123456789 corresponds to 111010110111100110100010101 hahahaha.

    I understand everything you just told me apart from the last line.

    t1 = ((tmr1h & 65535) * 65536) + (tmril & 65535)

    Would you care to explain what's going on here?

    Thanks for your patience
    Anduril explained is nicely... the reason for anding with 65535 is to strip away anything in the upper half of a 32 bit variable, preventing overlaps or overflows.

    65535 = 000000000000000001111111111111111 So only the lower 16 bits are used in each case.

  8. #8
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    Thanks for the explanations guys. I understand the bitwise operation of & and << now, I also understand the operation of both statements (is that meant to be an & between the two terms Anduril?)

    I'm still not completely clear as to what the anding process safeguards you against. Could you think of an example where the statement I came up with, t1 = (TMR1H*256) + TMR1L, could produce an erroneous result? And how the &'ing would fix that?

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    First, I need to point out a mistake in my previous post. I corrected it above, but it should be:
    Code:
    t1 = ((tmr1h & 0xFFFF) << 16) | (tmr1l & 0xFFFF);  // that should be a bitwise OR
    Now, say tmr1l contained a value too big to fit in 16 bits. Adding/ORing that plus the result of moving tmr1h left would result in an erroneous result since you would have overlapping bits. You can't take two 17-bit numbers and squeeze them all into a 32-bit space without throwing away 2 bits.

    Your example is meant to put two 8-bit values side by side. An example that would overflow would be any value of TMR1L or TMR1H that exceeds 255 if it's unsigned or is a negative value if it's signed.

    It's also worth noting that many compilers simplify multiplication by powers of two to << since shifting is quicker than multiplying. Thus, your compiler could actually be doing TMR1H << 8, and the << operator is undefined for negative numbers.

    Sorry, for the edits and reposting, my browser went crazy...

    Just noticed your last question. If you don't get how the &ing fixes that issue, then I don't think you fully understand bitwise &. Take the following:
    Code:
      Decimal    Hex        Binary
      987654     0xF1206    1111 0001 0010 0000 0110
    & 65535      0xFFFF     0000 1111 1111 1111 1111
      -------    -------    ------------------------
      4614       0x1206     0000 0001 0010 0000 0110
    Note that 0xFFFF is the same as 0x0000FFFF, just like 123 is the same as 0000123 (in regular numbers, ignoring the octal prefix convention). Since & only produces a 1 in a given bit if both operands have a 1 in that bit, the implicit 0's to the left of the F's in 0xFFFF "clear" those bits and make them 0's, thus your number is forced to fit in 16-bits. More reading and playing around with these would probably be your best bet, especially since it looks like you might be doing embedded stuff, and bit twiddling is pretty common there. Also, I personally find it easiest to work with bitwise operations in hex instead of decimal since it's easier to "see" what bits are on/off.
    Last edited by anduril462; 03-07-2011 at 06:26 PM.

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    Thanks for that excellent explanation Anduril! I now know exactly why I wasn't understanding what issue this anding was addressing,

    You are absolutely correct, I am doing embedded stuff. I am writing code for a PIC microcontroller and I wanted to put two 8 bit values taken from 8 bit registers side by side. Because the registers I am talking about only contain 8 bits, it's impossible for a value of say 256 to be contained in either! For this reason, I didn't even consider that a larger value than 8 bits could be contained in these two variables (which I now see is what this precaution was addressing!) If this was a possibility however, what you and Tater mentioned is an elegant precaution to take. I'm hoping my assumptions are correct; a number read from an 8 bit register can absolutely no way be over 255, if that's not the case then I'm throwing my PIC dev board out the window lol. If you know better, do enlighten me.

    I think I should have mentioned the embedded part a little earlier but I now know how to deal with numbers that could potentially be larger than where they are meant to fit.

    A very experienced programmer also mentioned about using hex to be able to 'see' what bits are on/off, I didn't know what he meant but looking at your example I can tell what you both mean - each digit represents 4 bits - how did I miss this before! Thanks for taking the time to clear everything up for me.

    Thanks for that excellent explanation Anduril! I now know exactly why I wasn't understanding what issue this anding was addressing.

    You are absolutely correct, I am doing embedded stuff. I am writing code for a PIC microcontroller and I wanted to put two 8 bit values taken from 8 bit registers side by side. Because the registers I am talking about can only contain 8 bits, a value of say 256 can't be contained in either. For this reason, I didn't even consider that TMR1H or TMR1L had larger value than 8 bit values in either. I see where you are coming from now - if this was a possibility what you and Tater mentioned is an elegant precaution to take. (I'm hoping my assumptions are correct though; a number read from an 8 bit register can never be over 255 - if that's not the case then I'm throwing my PIC dev board out the window lol).

    I think I should have mentioned the embedded part a little earlier but I now know how to deal with numbers that could potentially be larger than where they are meant to fit.

    A very experienced programmer also advised me to use hex to be able to 'see' what bits are on/off. I didn't know what he meant at the time but looking at your example I can tell what you both mean - each digit represents 4 bits. How did I miss this before! Thankyou for taking the time to clear this all up for me.
    Last edited by dannybeckett; 03-07-2011 at 08:01 PM.

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    LOL... Yeah I think you're pretty safe in assuming you won't get a value bigger than 255 out of an 8 bit register... and if you do, you should be looking for a new uC to play with...

    FWIW... maybe next time explain that you're combining PIC or uC registers... save us all a fair bit of confusion.

    For hex ... it's easy...

    Code:
    0000  0x0
    0001  0x1
    0010  0x2
    0011  0x3
    0100  0x4
    0101  0x5
    0110  0x6
    0111  0x7
    1000  0x8
    1001  0x9
    1010  0xA
    1011  0xB
    1100  0xC
    1101  0xD
    1110  0xE
    1111  0xF

  12. #12
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    hahahaha yeah I'll include all the facts next time I think At least I learned quite a lot! Yeah the whole hex system makes sense to me now, I think im more glad that's been de-mystified than the & operator!

  13. #13
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    I have 1 more question for you guys. I want to test wether the operations I am performing on this combined value are actually working, and the way I can do that is split the new value back up again in to 8 bits and stick it on two 8 bit ports to light leds.

    Code:
    #include <htc.h>
    #define _XTAL_FREQ 8000000
    __CONFIG (FOSC_XT & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF);
    
    void initDigitalOut() {
    	PORTA = PORTB = PORTC = PORTD = 0;
    	TRISA = TRISB = TRISC = TRISD = 0;
    	ANSEL = ANSELH = 0;
    }
    
    void test() {
    	int test = 0;
    	test = 0xFFFF&0xFFFF;
    	PORTB = test >> 10;
    }
    
    void main() {
    	initDigitalOut();
    	test();
    }
    What this should do is light 6 LEDs on PORTB (16 bit number shifted left 10 times). Instead it lights all 8. My only guess is that the data outside the scope of 'test' has 1s on it. I even shifted it 16 times bit they all stayed lit. Could this to do with me trying to operate outside the scope of test? I added the &0xFFFF but im guessing this is quite pointless becuse int can only be 16 bits long anyway (maybe even this is incorrect, since the microprocessor is 8 bits?)

    I'm guessing there is going to be a much easier way to achieve this than what im trying to do here. Sorry for the noob-ness.

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Of course it lights all 8 leds... 0xFFFF is a 16 bits (4 bits per hex digit) ...

    Try this...
    Code:
    temp = 0xFF00;   // an 8 bit number in the upper byte of 16 bits
    
    temp = temp >> 10;  // only 6 bits remain (0x3F)
    
    PORTB = test;
    You probably should concoct a small program on your PC for testing this stuff before you stuff it into the uC... I'm sure it would save you a ton of muss and fuss....
    Last edited by CommonTater; 03-08-2011 at 10:33 AM.

  15. #15
    Registered User
    Join Date
    Mar 2011
    Posts
    22
    0xFFFF shifted left 10 times should now read 0x3F the same as 0xFF00 would, or is that wrong? I'm assuming PORTB = temp in your example, unfortunately that didn't work either! all 8 LEDs lit up on PORTB and I dont know why.

    The reason why I text it on the MCU is because unexpected things like this happen so I want to make sure it runs fine on the controller before moving on. It's not so bad writing the code onto the controller anyway, takes max 10 seconds from the compile to chip execution.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. dark side of global variables
    By MK27 in forum C Programming
    Replies: 18
    Last Post: 12-09-2008, 03:14 AM
  2. A very long list of questions... maybe to long...
    By Ravens'sWrath in forum C Programming
    Replies: 16
    Last Post: 05-16-2007, 05:36 AM
  3. Creating one variable from two
    By Peter_D3T in forum C++ Programming
    Replies: 4
    Last Post: 06-20-2002, 01:39 PM
  4. creating a filename based on a variable
    By Waldo2k2 in forum C++ Programming
    Replies: 3
    Last Post: 05-22-2002, 05:27 PM
  5. Im so lost at . .
    By hermit in forum C Programming
    Replies: 18
    Last Post: 05-15-2002, 01:26 AM