Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

We use Integer type represent index variables most of the time. But in some situations, we're forced to choose

std::vector<int> vec;
....

for(int i = 0; i < vec.size(); ++i)
....

This will cause the compiler to raise the warning that mixed use of signed/unsigned variables. if I make the index variable as for( size_t i = 0; i < vec.size(); i++ ), (or an unsigned int )it will sort out the issues.

When it come more specific to use windows types, most of the Windows APIs are dealing with DWORD (which typedef-ed as unsigned long).

So when I use similar iteration, will again cause the same warning. Now if I rewrite it as

DWORD dwCount;
....

for(DWORD i = 0; i < dwCount; ++i)
....

I find this a bit weird. It might be the problem withe perceptions.

I agree that we are supposed to use the same type of index variable to avoid the range problems can happen with the index variables. For e.g if we're using

_int64 i64Count; // 
....

for(_int64 i = 0; i < i64Count; ++i)
....

But in the case of DWORD, or unsigned integers, are there any problems in rewriting it as

for(int i = 0; (size_t)i < vec.size(); ++i)

How most of the people are working with similar issues?

share|improve this question
3  
Why would you use a signed integer to represent index? That's like using vector of integers to store a string. –  Let_Me_Be Aug 30 '11 at 9:46
    
@Let_Me_Be: Because it makes the boundary conditions easier to test. For example on a count down to zero, a less-than test before executing the loop body cannot work with an unsigned value. Similarly a count up to the maximum doesn't work. Of course in that case a signed integer won't work either (because it can't represent such a large value). –  Yttrill Jan 13 '12 at 20:03

7 Answers 7

std::vector<int> vec;

for(int i = 0; i < vec.size(); ++i)

Use an iterator for this, not a for loop.

For the others, as long as the variable type is of the same size, static_cast should work just fine (i.e. DWORD to int16_t)

share|improve this answer
1  
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i) is a pain to write. Having for (auto i = vec.begin();... is a whole lot more readable. Of course, foreach is also in C++11. –  David Thornley Aug 30 '11 at 14:12

vector has a typedef that tells you the correct type to use :-

for(std::vector<int>::size_type i = 0; i < thing.size(); ++i)
{
}

It's almost always defined to be size_t though but you can't rely on that

share|improve this answer
3  
Not really an improvement in readability, IMHO. –  Doc Brown Aug 30 '11 at 13:12
    
No, but as it's the only way to tell what is the correct type to use for an index into the vector, that doesn't really matter... –  JohnB Aug 30 '11 at 13:26
    
Ouch, that's ugly! I'm finding more and more enjoyment in C++ by the day, for all the wrong reasons. –  Mihai Danila Jan 1 at 6:30
1  
These days in c++11 just use auto –  JohnB Jan 1 at 9:37

The case you described is one of the things I dislike in C++, too. But I have learned to live with that, either by using

for( size_t i = 0; i < vec.size(); i++ )

or

for( int i = 0; i < (int)vec.size(); i++ )

(of course, the latter only when there is no risk of getting some int overflow).

share|improve this answer

Yep, it is a pain and also one of the best use-cases for the C++ 11 keyword auto:

for (auto i = 0; i < vec.size(); ++i)
share|improve this answer
4  
But shouldn't this just delcare i as int, because 0 is an int literal and the auto keyword doesn't "look ahead" to the i < vec.size() expression? Or is a for loop treated with special intelligence by the compiler? –  Christian Rau Aug 30 '11 at 16:48
    
@Cristian: Yes, a good catch. auto works well with iterators because you initialize it with vec.begin(). Unfortunatelly, with indices that does not work. My bad :) –  Nemanja Trifunovic Aug 30 '11 at 17:02
    
Please adjust your answer; not everyone reading it will also read the comments. –  Mihai Danila Jan 1 at 6:31

The reason it's warning you about comparison between signed and unsigned is because the signed value will likely be converted to unsigned, which might not be what you expect.

In your example (comparing int to size_t), int will be implicitly converted to size_t (unless int somehow has a larger range than size_t). Thus, if the int is negative, it will likely be greater than the value you're comparing it to due to wraparound. This won't be a problem if your index is never negative, but you'll still get that warning.

Instead, use an unsigned type (such as unsigned int, size_t, or, as John B recommends, std::vector<int>::size_type) for your index variable:

for(unsigned int i = 0; i < vec.size(); i++)

Be careful when counting down, though:

for(unsigned int i = vec.size()-1; i >= 0; i--) // don't do this!

The above will not work because i >= 0 is always true when i is unsigned. Instead, use the "arrow operator" for loops that count down:

for (unsigned int i = vec.size(); i-- > 0; )
    vec[i] = ...;

As other answers point out, you normally want to use an iterator to traverse a vector. Here's the C++11 syntax:

for (auto i = vec.begin(); i != vec.end(); ++i)
share|improve this answer

I use a cast to int, as in for (int i = 0; i < (int)v.size(); ++i). Yes, it's ugly. I blame it on the stupid design of the standard library where they decided to use unsigned integers to represent sizes. (In order to.. what? extend the range by one bit?)

share|improve this answer
    
In what situation would a collection size of negative anything be meaningful? Using unsigned integers for various collection sizes seems like the sensible choice, to me. Last I checked, taking the length of a string rarely returned a negative result either... –  Michael Kjörling Aug 31 '11 at 8:11
    
In what situation would it be meaningful for simple test such as if(v.size()-1 > 0) { ... } to return true for an empty container? The problem is that sizes are also often used in arithmetic, esp. with index-based containers, which is asking for trouble given that they're unsigned. Basically, using unsigned types for anything else than 1) bitwise manipulations, or 2) modular arithmetic is calling for trouble. –  zvrba Sep 1 '11 at 6:11
1  
good point. While I don't really see the point of your particular example (I would probably just write if(v.size() > 1) { ... } since that makes the intent more clear, and as an added bonus the issue of signed/unsigned becomes void), I do see how in some specific cases signedness might be useful. I stand corrected. –  Michael Kjörling Sep 2 '11 at 20:59
    
@Michael: I agree it was contrived example. Still, I often write algorithms with nested loops: for(i=0;i<v.size()-1;++i) for(j=i+1;j<v.size();++j) .. if v is empty, the outer loop executes (size_t)-1 times. So I either have to check v.empty() before the loop or cast v.size() to a signed type, both of which I personally think are ugly workarounds. I choose a cast as it's fewer LOC, no if()s => fewer possibilites for mistake. (Also, in 2nd complement, conversion oveflow returns a negative number, so the loop doesn't execute at all.) –  zvrba Sep 3 '11 at 9:44

A new option for C++11, you can do things like the following

for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}

and

for(decltype(dWord) i = 0; i < dWord; ++i) {...}

While it repeats a little more than the basic for-loop would, it's not nearly as long-winded as pre-'11 ways of specifying values, and using this pattern consistently will work for most, if not all, possible terms you'd want to compare against, which makes it great for code refactoring. It even works for simple cases like this:

int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)

Furthermore, while you should use auto whenever you're setting i to some intelligent value (like vec.begin()), decltype works when you're setting to a constant like zero, where auto would just resolve that to int because 0 is a simple integer literal.

To be honest, I'd like to see a compiler mechanism for extending the auto type-determination for loop incrementers to look at the value being compared against.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.