views:

147

answers:

3

Hello there - first post so apologies if I make some mistakes,

I am currently working through Accelerated C++ and have come across my first 'issue' in exercise 2-3.

A quick overview of the program - the program basically takes a name, then displays a greeting within a frame of asterisks - i.e. Hello ! surrounded framed by *'s.

The exercise - In the example program, the authors use 'const int' to determine the 'padding' (blank spaces) between the greeting and the asterisks. They then ask the reader, as part of the exercise, to ask the user for input as to how big they want the padding to be.

All this seems easy enough, I go ahead ask the user for two integers (int) and store them and change the program to use these integers, removing the ones used by the author, when compiling though I get the following warning;

 Exercise2-3.cpp:46: warning: comparison between signed and unsigned integer expressions

After some research it appears to be because the code attempts to compare one of the above integers (int) to a string::size_type, which is fine. But I was wondering - does this mean I should change one of the integers to an unsigned int? Is it important to explicitly state whether my ints are signed or unsigned?

 cout << "Please enter the size of the frame between top and bottom you would like ";
 int padtopbottom;
 cin >> padtopbottom;

 cout << "Please enter size of the frame from each side you would like: ";
 unsigned int padsides; 
 cin >> padsides;

 string::size_type c = 0; // definition of c in the program
 if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs

Above are the relevant bits of code, the c is of type string::size_type because we do not know how long the greeting might be - but why do I get this problem now, when the author's code didn't get the problem when using const int? In addition - to anyone who may have completed Accelerated C++ - will this be explained later in the book?

I am on Linux Mint using g++ via Geany btw, if that helps make a difference as I read that could make a different when determining string::size_type.

Thanks for any guidance

+2  A: 

It is usually a good idea to declare variables as unsigned if they will be compared to sizes, to avoid this issue.

Compilers give warnings about comparing signed and unsigned types because the ranges of signed and unsigned ints are different, and when they are compared to one another, the results can be surprising. If you have to make such a comparison, you should explicitly cast one of the values to be compatible with the other, perhaps after checking to ensure that the value you are casting is valid. For example:

unsigned int u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();

if (i >= 0)
{
    // i is nonnegative, so it is safe to compare to unsigned value
    if ((unsigned)i >= u)
        BlahBlahBlah();
    else
        YaddaYaddaYadda();
}
else
{
    HandleNegativeValue();
}
Kristopher Johnson
A: 

At the extreme ranges an unsigned int can get begger than an int.
Therefore the compiler generates a warning. If you are sure that this is not a problem feel free to cast the types to the same type so the warning disappears (use C++ cast so they are easy to spot).

Alternatively make the variables the same type to stop the compiler complaining.
I mean is it possable to have a negative padding? If so then keep int. Otherwise you should probably use unsigned int and let the stream catch the situations where the user types in a negative number.

Martin York
A: 

The important difference between signed and unsigned ints is the interpretation of the last bit. The last bit in signed types represent the sign of the number, meaning: e.g:

0001 is 1 signed and unsigned 1001 is -1 signed and 9 unsigned

(I avoided the whole complement issue for clarity of explanation! This is not exactly how ints are represented in memory!)

You can imagine that it makes a difference to know if you compare with -1 or with +9. In many cases, programmers are just too lazy to declare counting ints as unsigned (bloating the for loop head f.i.) It is usually not an issue because with ints you have to count to 2^31 until your sign bit bites you. That's why it is only a warning. Because we are too lazy to write 'unsigned' instead of 'int'.

AndreasT
Ah I see - I have now changed the counting int as unsigned. Is this considered good practice, or even bad practice? :)
Tim Harrington
Please, if you downvote, shortly explain why. Even if it is only one word. I can't see anyhting wrong with my answer. Which might be a problem you can help me with.
AndreasT
@Tim: "unsigned" is a synonym for "unsigned int". You should use unsigned int or the stl standard counting/iterating variable type std::size_t (which is a synonym as well). It is a best practice to use unsigned in all cases of "iterate over elements 0 to n". It improves clarity and removes warnings, so it is a winner ;-)
AndreasT