This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

cast?

Does anybody know, how one have to cast an operation correctly? And is it necessary to tell the compiler that a constant is unsined long

#define dword unsigned long
unsigned char ucH;    //hours
unsigned char ucM;    //minutes
unsigned char ucS;    //seconds
dword ulTime;         //Time in s

GetTime(...);
ulTime = ucS + ucM*60 + ucH*3600;
[..]
this won't work! How do I have to cast the calculation?

ulTime = (dword)(ucS + ucM*60 + ucH*3600);
or
ulTime = ucS + (dword)ucM*60 + (dword)ucH*3600);
or ???

I have tried to find any written description (K&R, C166-Reference) but I could't find anything about this theme!

Do I have to use 3600 or 3600ul?

Thank you
...Leo

Parents
  • #define dword unsigned long
    unsigned char ucH;    //hours
    unsigned char ucM;    //minutes
    unsigned char ucS;    //seconds
    dword ulTime;         //Time in s
    
    GetTime(...);
    ulTime = ucS + ucM*60 + ucH*3600;
    The statement you have can be rewritten using only types as:
    (ulong) = (uchar) + (uchar) * (int) + (uchar) * (int);
    Now, ANSI has very strict rules for how these operations are performed. In ANSI...
    char * int  = int
    char * long = long
    int  * long = long
    int  * int  = int
    ANSI promotion rules will fit the result of an operation to the size of the "largest" operand, but no larger (typically).

    So, Looking back at your code...
    (ulong) = (uchar) + (uchar) * (int) + (uchar) * (int);
    
       /* Is reduced to */
    
    (ulong) = (uchar) + (int) + (int);
    
       /* Which is reduced to */
    
    (ulong) = (int) + (int);
    
       /* Which is further reduced to */
    
    (ulong) = (int);
    I guess from this you are seeing a result that is REALLY not what you expected.

    The easiest solution is to change the code so that operations (+, -, *, /) are performed according to ANSI rules generating the sized results that you want. This would be the following:
    ulTime = ucS + ucM * 60UL + ucH * 3600UL;
    By changing 60 and 3600 to unsigned longs, you are changing the types of the operands. And, now, you'll get...
    (ulong) = (uchar) + (uchar) * (ulong) + (uchar) * (ulong);
    
       /* Is reduced to */
    
    (ulong) = (uchar) + (ulong) + (ulong);
    
       /* Which is reduced to */
    
    (ulong) = (ulong) + (ulong);
    
       /* Which is further reduced to */
    
    (ulong) = (ulong);
    And, that's precisely what you want.

    Jon

Reply
  • #define dword unsigned long
    unsigned char ucH;    //hours
    unsigned char ucM;    //minutes
    unsigned char ucS;    //seconds
    dword ulTime;         //Time in s
    
    GetTime(...);
    ulTime = ucS + ucM*60 + ucH*3600;
    The statement you have can be rewritten using only types as:
    (ulong) = (uchar) + (uchar) * (int) + (uchar) * (int);
    Now, ANSI has very strict rules for how these operations are performed. In ANSI...
    char * int  = int
    char * long = long
    int  * long = long
    int  * int  = int
    ANSI promotion rules will fit the result of an operation to the size of the "largest" operand, but no larger (typically).

    So, Looking back at your code...
    (ulong) = (uchar) + (uchar) * (int) + (uchar) * (int);
    
       /* Is reduced to */
    
    (ulong) = (uchar) + (int) + (int);
    
       /* Which is reduced to */
    
    (ulong) = (int) + (int);
    
       /* Which is further reduced to */
    
    (ulong) = (int);
    I guess from this you are seeing a result that is REALLY not what you expected.

    The easiest solution is to change the code so that operations (+, -, *, /) are performed according to ANSI rules generating the sized results that you want. This would be the following:
    ulTime = ucS + ucM * 60UL + ucH * 3600UL;
    By changing 60 and 3600 to unsigned longs, you are changing the types of the operands. And, now, you'll get...
    (ulong) = (uchar) + (uchar) * (ulong) + (uchar) * (ulong);
    
       /* Is reduced to */
    
    (ulong) = (uchar) + (ulong) + (ulong);
    
       /* Which is reduced to */
    
    (ulong) = (ulong) + (ulong);
    
       /* Which is further reduced to */
    
    (ulong) = (ulong);
    And, that's precisely what you want.

    Jon

Children
  • #define dword unsigned long
    unsigned char ucH;    //hours
    unsigned char ucM;    //minutes
    unsigned char ucS;    //seconds
    dword ulTime;         //Time in s
    
    ulTime = ucS + ucM * 60UL + ucH * 3600UL;
    

    ucS and ucM are unsigned char, so they each have a maximum value of 255. 255 + 60 * 255 is 15555, well within the range of an int, so the constant sixty doesn't have to be an unsigned long.

    255 * 3600 is 918000, way beyond what a 16-bit int can hold. Even if we assume ucH will have a maximum value of 23, 23 * 3600 is 82800, again too big for an int, so the 3600 does have to be 3600UL.

    -- Gary Culp

  • ucS and ucM are unsigned char, so they each have a maximum value of 255. 255 + 60 * 255 is 15555, well within the range of an int, so the constant sixty doesn't have to be an unsigned long.

    Ahhh. Yes. You are right about that. I noticed that the multiplication with 3600 would definitely be out of range and assumed that the multiplication with 60 would be as well (assuming that NOINTPROMOTE is used.)

    Jon

  • Hi Jon,
    thank you for your detailed reply. I will check whether your suggestion will work in all cases or not :-). I hope fervently that C166 will keep to ANSI-C!

    And thanks to the other repiers too - of course!

    ...Leo

  • I will check whether your suggestion will work in all cases or not :-). I hope fervently that C166 will keep to ANSI-C!

    The C166 compiler is ANSI compliant as tested using the test suites that we have.

    My suggestion is one of many ways to do things, but it should work with ANY ANSI C compilter.

    Jon