-
August 3rd, 2010, 10:57 AM
#1
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.
-
August 3rd, 2010, 11:05 AM
#2
Re: signed to unsigned (and vice versa)
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
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.
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
-
August 3rd, 2010, 12:33 PM
#3
Re: signed to unsigned (and vice versa)
Originally Posted by laserlight
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
-
August 3rd, 2010, 12:41 PM
#4
Re: signed to unsigned (and vice versa)
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".
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.
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.
-
August 3rd, 2010, 01:04 PM
#5
Re: signed to unsigned (and vice versa)
Originally Posted by laserlight
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
-
August 3rd, 2010, 01:08 PM
#6
Re: signed to unsigned (and vice versa)
Oh, I misread your statement. You stated:
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.
-
August 3rd, 2010, 01:38 PM
#7
Re: signed to unsigned (and vice versa)
Originally Posted by laserlight
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
-
August 3rd, 2010, 01:54 PM
#8
Re: signed to unsigned (and vice versa)
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:
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.
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.
-
August 4th, 2010, 03:35 AM
#9
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.
-
August 4th, 2010, 04:10 AM
#10
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 ...
-
August 4th, 2010, 04:34 AM
#11
Re: signed to unsigned (and vice versa)
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?
-
August 4th, 2010, 04:58 AM
#12
Re: signed to unsigned (and vice versa)
Originally Posted by superbonzo
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?
Originally Posted by laserlight
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.
-
August 4th, 2010, 05:11 AM
#13
Re: signed to unsigned (and vice versa)
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?
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
-
August 4th, 2010, 05:12 AM
#14
Re: signed to unsigned (and vice versa)
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.
-
August 4th, 2010, 05:28 AM
#15
Re: signed to unsigned (and vice versa)
Originally Posted by superbonzo
ps. I just quickly tested the above with the online Comeau compiler ... so you should check it
Thanks. I'll check it out.
Originally Posted by laserlight
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|