static_cast<unsigned short)( -1 ) Well defined?

Discussion in 'C++' started by Jim Langston, Nov 21, 2006.

  1. Jim Langston

    Jim Langston Guest

    Is the following well defined?

    size_t IntVal = 65537;
    unsigned short Length;

    if ( IntVal > static_cast<unsigned short>( -1 ) )
    {
    std::cout << "Value too long to fit in a short" << std::endl;
    }
    else
    {
    std::cout << "Value fits" << std::endl;
    Length = static_cast<unsigned short>( IntVal );
    }

    What I'm actually going to be using it for is to send a length short through
    sockets, and I want to ensure that the length isn't greater than 65535.
    Rather than the magic number, I was thinking that static_cast<unsigned
    short>( -1 ) would be better. Is this well defined? Will it equal 65535 in
    all cases where a short is a 2 byte integer?
     
    Jim Langston, Nov 21, 2006
    #1
    1. Advertising

  2. Jim Langston

    Kai-Uwe Bux Guest

    Jim Langston wrote:

    > Is the following well defined?
    >
    > size_t IntVal = 65537;
    > unsigned short Length;
    >
    > if ( IntVal > static_cast<unsigned short>( -1 ) )
    > {
    > std::cout << "Value too long to fit in a short" << std::endl;
    > }
    > else
    > {
    > std::cout << "Value fits" << std::endl;
    > Length = static_cast<unsigned short>( IntVal );
    > }
    >
    > What I'm actually going to be using it for is to send a length short
    > through sockets, and I want to ensure that the length isn't greater than
    > 65535.


    If that is want you want to check, you should say so:

    if ( IntVal > 65535 ) { ...


    > Rather than the magic number, I was thinking that
    > static_cast<unsigned short>( -1 ) would be better.


    Why? If you want to check > 65535, then presumably, your specs contain a
    magic number. Your code should reflect that.

    > Is this well defined?


    Your code has implementation defined behavior. Moreover, it is guaranteed,
    that for IntVal <= 65535, the "Value fits" branch will be taken.

    > Will it equal 65535 in all cases where a short is a 2 byte integer?


    Yes, provided your bytes have eight bits. However, your bytes maybe longer
    and your shorts may have more than 2 bytes.


    Now, you need to distinguish whether you want to check

    (a) whether IntVal <= 65536, or
    (b) whether IntVal can be faithfully represented as a short unsigned.

    Your code does the later, and as far as I can see, it does so correctly.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Nov 21, 2006
    #2
    1. Advertising

  3. Jim Langston

    Salt_Peter Guest

    Re: static_cast<unsigned short)( -1 ) Well defined?

    Jim Langston wrote:
    > Is the following well defined?
    >
    > size_t IntVal = 65537;
    > unsigned short Length;
    >
    > if ( IntVal > static_cast<unsigned short>( -1 ) )
    > {
    > std::cout << "Value too long to fit in a short" << std::endl;
    > }
    > else
    > {
    > std::cout << "Value fits" << std::endl;
    > Length = static_cast<unsigned short>( IntVal );
    > }
    >
    > What I'm actually going to be using it for is to send a length short through
    > sockets, and I want to ensure that the length isn't greater than 65535.
    > Rather than the magic number, I was thinking that static_cast<unsigned
    > short>( -1 ) would be better. Is this well defined? Will it equal 65535 in
    > all cases where a short is a 2 byte integer?


    I doubt that can be enforced or guarenteed other than by checking
    dutifully- but i may be wrong.
    take a look at:
    template<>
    struct numeric_limits<unsigned short>
    in...
    #include <limits>

    namespace Project {
    typedef unsigned short usocket;
    };

    int main()
    {
    using Project::usocket;
    using std::numeric_limits;
    std::cout << "numeric_limits< usocket >::min() ";
    std::cout << numeric_limits< usocket >::min();
    std::cout << std::endl;
    std::cout << "numeric_limits< usocket >::max() ";
    std::cout << numeric_limits< usocket >::max();
    std::cout << std::endl;

    int n(65530);
    for(size_t t = 0; t < 10; ++t)
    {
    std::cout << "n++ = " << n++;
    usocket usock(static_cast<usocket>(n));
    std::cout << "\tusock = " << usock;
    std::cout << std::endl;
    }
    }

    /*
    numeric_limits< usocket >::min() 0
    numeric_limits< usocket >::max() 65535
    n++ = 65530 usock = 65531
    n++ = 65531 usock = 65532
    n++ = 65532 usock = 65533
    n++ = 65533 usock = 65534
    n++ = 65534 usock = 65535
    n++ = 65535 usock = 0
    n++ = 65536 usock = 1
    n++ = 65537 usock = 2
    n++ = 65538 usock = 3
    n++ = 65539 usock = 4
    */
     
    Salt_Peter, Nov 21, 2006
    #3
  4. Jim Langston:

    > Is the following well defined?
    >
    > size_t IntVal = 65537;



    Slight problem here.

    The range guaranteed for size_t is:

    0 through 65535

    On a system which has:

    unsigned int : 16-Bit
    unsigned long : 32-Bit
    size_t : 16-Bit

    , then this definition would be interpreted as:

    size_t IntVal = 65537LU;

    When converting to "size_t" the overflow would wrap around, making the
    definition equivalent to:

    size_t IntVal = 2;


    > unsigned short Length;
    >
    > if ( IntVal > static_cast<unsigned short>( -1 ) )



    If you convert -1 to a unsigned integer type, then you're left with the
    maximum value for that unsigned integer type. E.g.

    char unsigned i = -1; char unsigned i = UCHAR_MAX;

    short unsigned i = -1; short unsigned i = USHRT_MAX;

    and so on...

    Before the comparison takes place, the unsigned short value will be either
    promoted to "int" or "unsigned int". Next, the types of the two operands will
    be matched, possible yielding something like:

    if ( (long unsigned)IntVal > (long unsigned)USHRT_MAX )


    > {
    > std::cout << "Value too long to fit in a short" << std::endl;
    > }
    > else
    > {
    > std::cout << "Value fits" << std::endl;
    > Length = static_cast<unsigned short>( IntVal );
    > }
    >
    > What I'm actually going to be using it for is to send a length short
    > through sockets, and I want to ensure that the length isn't greater than
    > 65535. Rather than the magic number, I was thinking that
    > static_cast<unsigned short>( -1 ) would be better. Is this well
    > defined? Will it equal 65535 in all cases where a short is a 2 byte
    > integer?



    To be honest, I'd have to read through the code in detail to see exactly what
    you're trying to do... things to watch out for though are:

    (1) Integer promotion (specifically, the possibility of "unsigned short"
    promoting to "unsigned int" rather than "signed int").
    (2) The range of "size_t" -- I'm not sure, but I think you could conceivably
    have a system where:

    typedef char unsigned size_t;

    Of course, on such a system, a byte would have to be at least 16-Bit, but I
    think you might want to watch out for:

    sizeof(short unsigned) > sizeof(size_t)

    Of course, sizeof doesn't tell us how many value representation bits an
    integer type has. To determine this, we can use the C-Style macro entitled
    "IMAX_BITS" (Google for it), or we can use numeric_limits.

    --

    Frederick Gotham
     
    Frederick Gotham, Nov 21, 2006
    #4
  5. Jim Langston

    Jim Langston Guest

    "Frederick Gotham" <> wrote in message
    news:dOD8h.16240$...
    > Jim Langston:
    >
    >> Is the following well defined?
    >>
    >> size_t IntVal = 65537;

    >
    >
    > Slight problem here.
    >
    > The range guaranteed for size_t is:
    >
    > 0 through 65535
    >
    > On a system which has:
    >
    > unsigned int : 16-Bit
    > unsigned long : 32-Bit
    > size_t : 16-Bit
    >
    > , then this definition would be interpreted as:
    >
    > size_t IntVal = 65537LU;


    On my compiler size_t is defined thusly:

    #ifndef _SIZE_T_DEFINED
    #ifdef _WIN64
    typedef unsigned __int64 size_t;
    #else
    typedef _W64 unsigned int size_t;
    #endif
    #define _SIZE_T_DEFINED
    #endif

    Basically an int. I'm not sure how it's defined on the 64 bit platform
    (things that suggest they would go to 64 bit with the _W64 didnt'
    necessarily).

    >
    > When converting to "size_t" the overflow would wrap around, making the
    > definition equivalent to:
    >
    > size_t IntVal = 2;
    >
    >
    >> unsigned short Length;
    >>
    >> if ( IntVal > static_cast<unsigned short>( -1 ) )

    >
    >
    > If you convert -1 to a unsigned integer type, then you're left with the
    > maximum value for that unsigned integer type. E.g.
    >
    > char unsigned i = -1; char unsigned i = UCHAR_MAX;
    >
    > short unsigned i = -1; short unsigned i = USHRT_MAX;
    >
    > and so on...
    >
    > Before the comparison takes place, the unsigned short value will be either
    > promoted to "int" or "unsigned int". Next, the types of the two operands
    > will
    > be matched, possible yielding something like:
    >
    > if ( (long unsigned)IntVal > (long unsigned)USHRT_MAX )
    >
    >
    >> {
    >> std::cout << "Value too long to fit in a short" << std::endl;
    >> }
    >> else
    >> {
    >> std::cout << "Value fits" << std::endl;
    >> Length = static_cast<unsigned short>( IntVal );
    >> }
    >>
    >> What I'm actually going to be using it for is to send a length short
    >> through sockets, and I want to ensure that the length isn't greater than
    >> 65535. Rather than the magic number, I was thinking that
    >> static_cast<unsigned short>( -1 ) would be better. Is this well
    >> defined? Will it equal 65535 in all cases where a short is a 2 byte
    >> integer?

    >
    >
    > To be honest, I'd have to read through the code in detail to see exactly
    > what
    > you're trying to do... things to watch out for though are:
    >
    > (1) Integer promotion (specifically, the possibility of "unsigned short"
    > promoting to "unsigned int" rather than "signed int").
    > (2) The range of "size_t" -- I'm not sure, but I think you could
    > conceivably
    > have a system where:
    >
    > typedef char unsigned size_t;
    >
    > Of course, on such a system, a byte would have to be at least 16-Bit, but
    > I
    > think you might want to watch out for:
    >
    > sizeof(short unsigned) > sizeof(size_t)
    >
    > Of course, sizeof doesn't tell us how many value representation bits an
    > integer type has. To determine this, we can use the C-Style macro entitled
    > "IMAX_BITS" (Google for it), or we can use numeric_limits.
    >
    > --
    >
    > Frederick Gotham
     
    Jim Langston, Nov 21, 2006
    #5
  6. Jim Langston:

    > On my compiler size_t is defined thusly:
    >
    > #ifndef _SIZE_T_DEFINED
    > #ifdef _WIN64
    > typedef unsigned __int64 size_t;
    > #else
    > typedef _W64 unsigned int size_t;
    > #endif
    > #define _SIZE_T_DEFINED
    > #endif
    >
    > Basically an int. I'm not sure how it's defined on the 64 bit platform
    > (things that suggest they would go to 64 bit with the _W64 didnt'
    > necessarily).



    I've no doubt that the code might work on your platform, or even on the
    majority of platforms. And I've not doubt that your compiler documentation
    might even define the behaviour of the code.

    All I can tell you is that the behaviour of the snippet is not defined by the
    C++ Standard.

    --

    Frederick Gotham
     
    Frederick Gotham, Nov 21, 2006
    #6
  7. Jim Langston

    Jack Klein Guest

    On Tue, 21 Nov 2006 14:11:21 GMT, Frederick Gotham
    <> wrote in comp.lang.c++:

    > Jim Langston:
    >
    > > Is the following well defined?
    > >
    > > size_t IntVal = 65537;

    >
    >
    > Slight problem here.
    >
    > The range guaranteed for size_t is:
    >
    > 0 through 65535
    >
    > On a system which has:
    >
    > unsigned int : 16-Bit
    > unsigned long : 32-Bit
    > size_t : 16-Bit
    >
    > , then this definition would be interpreted as:
    >
    > size_t IntVal = 65537LU;


    No, you're quite incorrect. Check the C++ standard. An unsuffixed
    decimal literal never has an unsigned type. On a platform where int
    has 16 bits:

    size_t IntVal = 65537;

    ....is exactly equivalent to:

    size_t IntVal = 65537L;

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Nov 21, 2006
    #7
  8. Jim Langston

    Bo Persson Guest

    Frederick Gotham wrote:
    > Jim Langston:
    >
    >> On my compiler size_t is defined thusly:
    >>
    >> #ifndef _SIZE_T_DEFINED
    >> #ifdef _WIN64
    >> typedef unsigned __int64 size_t;
    >> #else
    >> typedef _W64 unsigned int size_t;
    >> #endif
    >> #define _SIZE_T_DEFINED
    >> #endif
    >>
    >> Basically an int. I'm not sure how it's defined on the 64 bit
    >> platform (things that suggest they would go to 64 bit with the
    >> _W64 didnt' necessarily).

    >
    >
    > I've no doubt that the code might work on your platform, or even on
    > the majority of platforms. And I've not doubt that your compiler
    > documentation might even define the behaviour of the code.


    It does, even in 64 bit mode.

    >
    > All I can tell you is that the behaviour of the snippet is not
    > defined by the C++ Standard.


    We don't know that, unless we have checked all other defines used by the
    particular implementation. With the right options set, _W64 is #define'd to
    nothing. Then, if __int64 is #define'd as long, and long is big enough, it
    could be correct.


    Bo Persson
     
    Bo Persson, Nov 21, 2006
    #8
  9. Bo Persson:

    >> I've no doubt that the code might work on your platform, or even on
    >> the majority of platforms. And I've not doubt that your compiler
    >> documentation might even define the behaviour of the code.

    >
    > It does, even in 64 bit mode.



    This is comp.lang.c++. Here's a list of newsgroups that this newsgroup is
    not:

    comp.lang.c++.mswindows.64
    comp.lang.c++.playstation2
    comp.lang.c++.whatever.implementation.you.can.find

    I couldn't care less whether this code works on your interterrestial
    spaceship, all I'm saying is that its behaviour is not defined by the C++
    Standard. Here's another example of code I don't care about:

    int main()
    {
    int i = 65535;

    ++i;
    }

    Will this program crash? That depends on the implementation. In the context
    of portable code, the behaviour is undefined.

    If you want to write platform-specific code which makes presumptions which
    aren't necessitated by the Standard, then find another newsgroup.


    >> All I can tell you is that the behaviour of the snippet is not
    >> defined by the C++ Standard.

    >
    > We don't know that, unless we have checked all other defines used by the
    > particular implementation.



    We know that it's not portable.


    > With the right options set, _W64 is #define'd
    > to nothing. Then, if __int64 is #define'd as long, and long is big
    > enough, it could be correct.



    The behaviour of the code is implementation defined. Not only that though,
    the implementation is free to leave the behaviour as undefined (e.g. in the
    case of signed integer overflow).

    --

    Frederick Gotham
     
    Frederick Gotham, Nov 21, 2006
    #9
  10. Jim Langston

    Bo Persson Guest

    Frederick Gotham wrote:
    > Bo Persson:
    >
    >>> I've no doubt that the code might work on your platform, or even
    >>> on the majority of platforms. And I've not doubt that your
    >>> compiler documentation might even define the behaviour of the
    >>> code.

    >>
    >> It does, even in 64 bit mode.

    >
    >
    > This is comp.lang.c++. Here's a list of newsgroups that this
    > newsgroup is not:
    >
    > comp.lang.c++.mswindows.64
    > comp.lang.c++.playstation2
    > comp.lang.c++.whatever.implementation.you.can.find
    >
    > I couldn't care less whether this code works on your interterrestial
    > spaceship, all I'm saying is that its behaviour is not defined by
    > the C++ Standard. Here's another example of code I don't care about:
    >
    > int main()
    > {
    > int i = 65535;
    >
    > ++i;
    > }
    >
    > Will this program crash? That depends on the implementation. In the
    > context of portable code, the behaviour is undefined.
    >
    > If you want to write platform-specific code which makes
    > presumptions which aren't necessitated by the Standard, then find
    > another newsgroup.


    I hang around in other newsgroups too. Just thought you wanted it confirmed
    that you were right.

    >
    >
    >>> All I can tell you is that the behaviour of the snippet is not
    >>> defined by the C++ Standard.

    >>
    >> We don't know that, unless we have checked all other defines used
    >> by the particular implementation.

    >
    >
    > We know that it's not portable.


    It wasn't supposed to be portable, it is a part of one specific standard
    library implementation. Whether it actually is standard conformant must be
    on-topic here.

    >
    >
    >> With the right options set, _W64 is #define'd
    >> to nothing. Then, if __int64 is #define'd as long, and long is big
    >> enough, it could be correct.

    >
    >
    > The behaviour of the code is implementation defined. Not only that
    > though, the implementation is free to leave the behaviour as
    > undefined (e.g. in the case of signed integer overflow).


    We can't tell just from the snippet whether it is conformant or not. It
    depends on the definitions of the names _W64 and __int64, reserved to the
    implementation. With the proper definitions, it just could be.


    Bo Persson
     
    Bo Persson, Nov 22, 2006
    #10
  11. Bo Persson:

    > We can't tell just from the snippet whether it is conformant or not. It
    > depends on the definitions of the names _W64 and __int64, reserved to
    > the implementation. With the proper definitions, it just could be.



    It's implementation-defined as to whether the behaviour of the code is
    undefined.

    If you're interested, I started a thread over on comp.lang.c:

    http://groups.google.ie/group/comp.lang.c/browse_thread/thread/f2bcf2bb366de4
    4e/2156215b21253042?lnk=st&q=&rnum=1&hl=en#2156215b21253042

    (I posted on comp.lang.c rather than comp.lang.c++ as one tends to get better
    answers to these kinds of questions there.)

    --

    Frederick Gotham
     
    Frederick Gotham, Nov 22, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    845
    Kaz Kylheku
    Oct 17, 2006
  2. Bo Peng
    Replies:
    11
    Views:
    1,102
    Victor Bazarov
    Oct 20, 2006
  3. Ioannis Vranos

    unsigned short, short literals

    Ioannis Vranos, Mar 4, 2008, in forum: C Programming
    Replies:
    5
    Views:
    702
    Eric Sosman
    Mar 5, 2008
  4. Alex Vinokur
    Replies:
    9
    Views:
    953
    Gerhard Fiedler
    Mar 22, 2011
  5. junyangzou
    Replies:
    13
    Views:
    268
Loading...

Share This Page