CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    signed to unsigned (and vice versa)

    I'm looking for the exact rules according to standard of casting an integer type of signed type to an unsigned integer of the same rank, as well as the contrary (unsigned to signed).

    ie:
    signed char to unsigned char
    unsigned int to signed int
    etc...
    but not signed char to unsigned int.

    In particular, I want to know what happens on machines that do, or don't, use 2's complement. How they behave differently.

    Is it safe to write:

    Code:
    unsigned int max_value = -1;
    On any architecture?

    The answers I found on the internet were too shady for my tastes.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  2. #2
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by monarch_dodra
    I'm looking for the exact rules according to standard of casting an integer type of signed type to an unsigned integer of the same rank, as well as the contrary (unsigned to signed).
    Ah, that just means some quoting then
    Quote Originally Posted by C++03 Section 4.7 Paragraphs 1 to 3
    An rvalue of an integer type can be converted to an rvalue of another integer type. An rvalue of an enumeration type can be converted to an rvalue of an integer type.

    If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2**n where n is the number of bits used to represent the unsigned type). [Note: In a two's complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ]

    If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
    Quote Originally Posted by monarch_dodra
    Is it safe to write:
    Code:
    unsigned int max_value = -1;
    On any architecture?
    Yes. In fact, this is pretty much how the standard defines npos for std::basic_string.
    Last edited by laserlight; August 3rd, 2010 at 11:08 AM. Reason: 2n => 2**n, where ** denotes exponentiation
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  3. #3
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: signed to unsigned (and vice versa)

    Quote Originally Posted by laserlight View Post
    Ah, that just means some quoting then



    Yes. In fact, this is pretty much how the standard defines npos for std::basic_string.
    If I see it rightly the section 4.7 doesn't exactly define conversion from signed to unsigned. Or if we assume the 'otherwise' part also applies to conversions to unsigned, it therefore is "implementation-defined". Also, does the C++ standard really 'define' the implementation for std::basic_string::npos or is it a concrete implementation where it is defined by assigning -1?

    I would say a static_cast will do the job regardless of the implementation. And

    Code:
       unsigned int ui = -1;
    implicitly does a static cast but wouldn't necessarily help to get the maximum unsigned integer.

    For an integer representation using not two's-complement for negatives the bit representation of -1 could be 10000000000000000000000000000001 (one sign-bit and no complement) and I doubt very much that they would cast that to 0xfffffff.

    Regards, Alex

  4. #4
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by itsmeandnobodyelse
    If I see it rightly the section 4.7 doesn't exactly define conversion from signed to unsigned. Or if we assume the 'otherwise' part also applies to conversions to unsigned, it therefore is "implementation-defined".
    Yes, except that the standard does define what happens if the value "can be represented in the destination type".

    Quote Originally Posted by itsmeandnobodyelse
    Also, does the C++ standard really 'define' the implementation for std::basic_string::npos or is it a concrete implementation where it is defined by assigning -1?
    I am not sure if an implementation is permitted to differ as long as the net effect is the same, but the C++ standard does indeed define how npos should be defined, i.e., by initialising it with -1.

    Quote Originally Posted by itsmeandnobodyelse
    implicitly does a static cast but wouldn't necessarily help to get the maximum unsigned integer.

    For an integer representation using not two's-complement for negatives the bit representation of -1 could be 10000000000000000000000000000001 (one sign-bit and no complement) and I doubt very much that they would cast that to 0xfffffff.
    You might want to read paragraph 2 of section 4.7 of the 2003 edition of the C++ standard again. In particular, the comment on two's complement representation is a good hint as to why you are mistaken.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  5. #5
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: signed to unsigned (and vice versa)

    Quote Originally Posted by laserlight View Post
    Yes, except that the standard does define what happens if the value "can be represented in the destination type".


    I am not sure if an implementation is permitted to differ as long as the net effect is the same, but the C++ standard does indeed define how npos should be defined, i.e., by initialising it with -1.


    You might want to read paragraph 2 of section 4.7 of the 2003 edition of the C++ standard again. In particular, the comment on two's complement representation is a good hint as to why you are mistaken.
    You probably mean the

    ...
    [Note: In a two's complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ]
    ...
    Maybe I am dump but I can't see from that hint why a non-two's complement of -1 necessarily must be casted to an unsigned integer with all bits set.

    Isn't it just 'implementation-defined' ?

    (Even if so, the npos also would work if it is not the highest unsigned integer).

    Regards, Alex

  6. #6
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Oh, I misread your statement. You stated:
    Quote Originally Posted by itsmeandnobodyelse
    If I see it rightly the section 4.7 doesn't exactly define conversion from signed to unsigned.
    That is incorrect. The standard leaves as implementation defined conversion to a signed integer type if the value cannot be represented in the destination type. This is a consequence of paragraph 3.

    Paragraph 2, on the other hand, effectively means that conversion from a signed to an unsigned integer type is performed as if two's complement is always used, with respect to the value. If two's complement is not in use, the conversion results in a change in the bit pattern, if necessary (i.e., it is not true that "a non-two's complement of -1 necessarily must be casted to an unsigned integer with all bits set").
    Last edited by laserlight; August 3rd, 2010 at 01:32 PM.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  7. #7
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: signed to unsigned (and vice versa)

    Quote Originally Posted by laserlight View Post
    Oh, I misread your statement. You stated:

    That is incorrect. The standard leaves as implementation defined conversion to a signed integer type if the value cannot be represented in the destination type. This is a consequence of paragraph 3.

    Paragraph 2, on the other hand, effectively means that conversion from a signed to an unsigned integer type is performed as if two's complement is always used, with respect to the value. If two's complement is not in use, the conversion results in a change in the bit pattern, if necessary.
    That makes sense though I can't read that assertment from the paragraph 2.

    I would have said the "otherwise, the value is implementation-defined." of paragraph 3 applies also for the conversion from signed to unsigned in case of non-two's complement, cause there were two if's and only one 'otherwise'.


    Regards, Alex

  8. #8
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by itsmeandnobodyelse
    That makes sense though I can't read that assertment from the paragraph 2.
    Perhaps you will find the corresponding paragraph from the C standard easier to understand:
    Quote Originally Posted by C99 Section 6.3.1.3 Paragraph 2
    Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
    This means that if you are converting -1 to unsigned int, you compute -1 + UINT_MAX + 1 = UINT_MAX, regardless of whether one's complement, two's complement or sign and magnitude is used to represent signed integer types.

    Quote Originally Posted by itsmeandnobodyelse
    I would have said the "otherwise, the value is implementation-defined." of paragraph 3 applies also for the conversion from signed to unsigned in case of non-two's complement, cause there were two if's and only one 'otherwise'.
    That would not make sense though. Besides the fact that they are in two different paragraphs, the first if pertains to "the destination type is unsigned". If that otherwise pertains to the first if, then it means: if the destination type is not unsigned, then the value is implementation-defined. This obviously does not make sense, and would render the first part of paragraph 3 meaningless. Therefore, one can conclude that the otherwise must pertain to the second if, i.e., if the destination type is signed and the value cannot be represented in the destination type, then the value is implementation-defined.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  9. #9
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: signed to unsigned (and vice versa)

    Ok, thanks. I found my answers.

    Now for a new question.

    I need something like this:

    Code:
    template<typename T>
    void f(unsigned T, signed T)
    {
        ...
    }
    Which doesn't work. Any way to do it, without asking the user to explicitly provide both the signed and unsigned parameter.

    How can I compile-time assert that they are both the same rank, and the correct signed-ness? (without boost)
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  10. #10
    Join Date
    Oct 2008
    Posts
    1,456

    Re: signed to unsigned (and vice versa)

    if you cannot use boost or C++0x then you'll probably need to define a custom trait specialized for each signed/unsigned type

    Code:
    template <typename T> struct signed_t {};
    template <typename T> struct unsigned_t {};
    
    template <> struct signed_t<int> { typedef signed int type; };
    template <> struct unsigned_t<int> { typedef unsigned int type; };
    
    // ...
    
    template<class T> void f( typename unsigned_t<T>::type v1, typename signed_t<T>::type v2 );
    
    int main()
    {
    	f<int>(1,1);
    }
    of course, things get complicated if you want automatic type deduction ...

  11. #11
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by monarch_dodra
    How can I compile-time assert that they are both the same rank, and the correct signed-ness?
    Must they be of the same rank, or is it sufficient to check if they are of the same size?
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  12. #12
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by superbonzo View Post
    if you cannot use boost or C++0x then you'll probably need to define a custom trait specialized for each signed/unsigned type

    Code:
    template <typename T> struct signed_t {};
    template <typename T> struct unsigned_t {};
    
    template <> struct signed_t<int> { typedef signed int type; };
    template <> struct unsigned_t<int> { typedef unsigned int type; };
    
    // ...
    
    template<class T> void f( typename unsigned_t<T>::type v1, typename signed_t<T>::type v2 );
    
    int main()
    {
        f<int>(1,1);
    }
    of course, things get complicated if you want automatic type deduction ...
    Good idea.

    You seem to be implying there is a way to do it with C++0x/boost, what's on your mind?

    Quote Originally Posted by laserlight View Post
    Must they be of the same rank, or is it sufficient to check if they are of the same size?
    I would prefer same rank, but if I can't, same size is the next best thing.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  13. #13
    Join Date
    Oct 2008
    Posts
    1,456

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by monarch_dodra View Post
    You seem to be implying there is a way to do it with C++0x/boost, what's on your mind?
    you can use c++0x/boost type traits libraries to save on typing all those specializations

    BTW, thinking about it, if you need automatic type deduction and a finer control over function overloads, then you might want something like

    Code:
    template <typename T> struct enable_signed {};
    template <typename T> struct enable_unsigned {};
    
    template <> struct enable_signed<signed int> { typedef int type; };
    template <> struct enable_unsigned<unsigned int> { typedef int type; };
    
    // ...
    
    template <class U,class V, class enable_U = typename enable_signed<U>::type, class enable_V = typename enable_unsigned<V>::type >
    struct enable_signed_unsigned {};
    
    template <class U,class V, class enable_U = typename enable_unsigned<U>::type, class enable_V = typename enable_signed<V>::type >
    struct enable_unsigned_signed {};
    
    // ..
    
    template<class U,class V> enable_signed_unsigned<U,V> f( U u, V v );
    template<class U,class V> enable_unsigned_signed<U,V> f( U u, V v );
    
    // or template<class U,class V> void f( U u, V v, enable_signed_unsigned<U,V> ignoreme = enable_signed_unsigned<U,V>() );
    // or use some sort of dispatcher ...
    
    int main()
    {
    	f(1,1u); // calls first f
    	f(1u,1); // calls second f
    	f(1u,1u); // error
    	f(1,1); // error
    }
    ps. I just quickly tested the above with the online Comeau compiler ... so you should check it

  14. #14
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by monarch_dodra
    You seem to be implying there is a way to do it with C++0x/boost, what's on your mind?
    Probably the stuff from <type_traits>, to be introduced in the next version of the C++ standard library. Actually, I believe that it is already available in the TR1 extensions.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  15. #15
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: signed to unsigned (and vice versa)

    Quote Originally Posted by superbonzo View Post
    ps. I just quickly tested the above with the online Comeau compiler ... so you should check it
    Thanks. I'll check it out.

    Quote Originally Posted by laserlight View Post
    Probably the stuff from <type_traits>, to be introduced in the next version of the C++ standard library. Actually, I believe that it is already available in the TR1 extensions.
    That's a very interesting library. Thanks.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured