I am going trough the book "Accelerated C++" by Andrew Koenig and Barbara E. Moo and I have some questions about the main example in chap 2. The code can be summarized as below, and is compiling without warning/error with g++:
#include <string>
using std::string;
int main()
{
const string greeting = "Hello, world!";
// OK
const int pad = 1;
// KO
// int pad = 1;
// OK
// unsigned int pad = 1;
const string::size_type cols = greeting.size() + 2 + pad * 2;
string::size_type c = 0;
if (c == 1 + pad)
{;}
return 0;
}
However, if I replace const int pad = 1;
by int pad = 1;
, the g++ compiler will return a warning:
warning: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
if (c == 1 + pad)
If I replace const int pad = 1;
by unsigned int pad = 1;
, the g++ compiler will not return a warning.
I understand why g++ return the warning, but I am not sure about the three below points:
unsigned int
in order to compare with a std::string::size_type
? The compiler does not return a warning in that case but I am not sure if it is safe. const int pad = 1
. Is the compiler automatically converting the variable pad
to an unsigned int
? const int pad = 1;
by string::size_type pad = 1;
, but the meaning of the variable pad
is not really linked to a string size in my opinion. Still, would this be the best approach in that case to avoid having different types in the comparison? From the compiler point of view:
So the answers to your questions:
unsigned int
and std::string::size_type
. unsinged int
. If you are using std::string
with the default allocator (which is likely), then size_type
is actually size_t
.
[support.types]/6 defines that size_t
is
an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.
So it's not technically guaranteed to be a unsigned int
, but I believe it is defined this way in most cases.
Now regarding your second question: if you use const int something = 2
, the compiler sees that this integer is a) never negative and b) never changes, so it's always safe to compare this variable with size_t
. In some cases the compiler may optimize the variable out completely and simply replace all it's occurrences with 2
.
I would say that it is better to use size_type
everywhere where you are to the size of something, since it is more verbose.
Comparing signed and unsigned values is "dangerous" in the sense that you may not get what you expect when the signed value is negative (it may well behave as a very large unsigned value, and thus a > b
gives true
when a = -1
and b = 100
. (The use of const int
works because the compiler knows the value isn't changing and thus can say "well, this value is always 1, so it works fine here")
As long as the value you want to compare fits in unsigned int
(on typical machines, a little over 4 billion) is fine.
What the compiler warns about is the comparison of unsigned and signed integer types. This is because the signed integer can be negative and the meaning is counter intuitive. This is because the signed is converted to unsigned before comparison, which means the negative number will compare greater than the positive .
Is it safe to use an unsigned int in order to compare with a std::string::size_type? The compiler does not return a warning in that case but I am not sure if it is safe.
Yes, they are both unsigned and then the semantics is what's expected. If their range differs the narrower are converted to a wider type.
Why is the compiler not giving a warning with the original code const int pad = 1. Is the compiler automatically converting the variable pad to an unsigned int?
This is because how the compiler is constructed. The compiler parses and to some extent optimizes the code before warnings are issued. The important point is that at the point this warning is being considered the compiler nows that the signed integer is 1
and then it's safe to compare with a unsigned integer.
I could also replace const int pad = 1; by string::size_type pad = 1;, but the meaning of the variable pad is not really linked to a string size in my opinion. Still, would this be the best approach in that case to avoid having different types in the comparison?
If you don't want it to be constant the best solution would probably be to make it at least an unsigned integer type. However you should be aware that there is no guaranteed relation between normal integer types and sizes, for example unsigned int
may be narrower, wider or equal to size_t
and size_type
(the latter may also differ).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.