Visual studio compiler bug?

Joined
Mar 9, 2004
Messages
3,322
I was writing some c along the lines of:

Code:
for (i = 0, j = 0; i < hLength && j < length - hLength;)
	list[i + j] = (left[i] < right[j]) ? left[i++] : right[j++];

And noticed that visual studio's compiler does the post increment *before* the assignment. Nothing big I know, but I figured I'd throw it out here before I start looking for a report bugs section. I'm using visual studio 2005 professional and there are no updates that I'm aware of. (or the check for updates button is aware of either)
 
I'm not seeing that "bug" in VS 2005.

Code:
	int i, j, k;
	int a[] = {1, 200, 4, 600, 8, 1000};
	int b[] = {100, 2, 400, 6, 800, 10};

	for (i = 0, j = 0; i < 6 && j < 6;) {
		cout << i << " " << j << " " << a[i] << " " << b[j] << " ";
		k = (a[i] < b[j]) ? a[i++] : b[j++];
		cout << k << "\n";
	}

The output is correct, with the post increment working properly:
Code:
i j a[i] b[j] k
0 0 1    100  1
1 0 200  100  100
1 1 200  2    2
1 2 200  400  200
2 2 4    400  4
3 2 600  400  400
3 3 600  6    6
3 4 600  800  600
4 4 8    800  8
5 4 1000 800  800
5 5 1000 10   10
 
It's still working for me when modified and compiled as a regular c source file. You probably have a subtle bug in your code.
 
I just tried your code and got the same conclusion, it was doing it in a little programming assignment I have and a little test case I made to double check. Here's my little test case.
Code:
#include <stdio.h>

void test1()
{
	int list[] = { 1, 2, 3, 4, 5 };
	int i, index = 1;

	// using constant that compiler will optimize
	list[index] = (1) ? list[index++] : -1;
	for(i = 0; i < 5; i++)
		printf("%d ", list[i]);
	printf(": %d\n", index);
}

void test2()
{
	int list[] = { 1, 2, 3, 4, 5 };
	int i, index = 1;

	list[index] = (index) ? list[index++] : -1;
	for(i = 0; i < 5; i++)
		printf("%d ", list[i]);
	printf(": %d\n", index);
}

int main(void)
{
	test1();
	test2();

	return 0;
}

using cl.exe version 14.00.50727.42

Code:
Compiled with C extension: cl test.c
1 2 3 4 5 : 2
1 2 2 4 5 : 2

Compiled with cpp extension: (same code) cl test.cpp /EHsc
1 2 2 4 5 : 2
1 2 2 4 5 : 2

Before I added the functions to it (everything in main + manual reset of index to one), c++ was giving:
1 2 3 4 5 : 2
1 2 3 4 5 : 2

Maybe I'm crazy.

Testing results said:
gcc/g++ think its:
1 2 3 4 5 : 2
1 2 3 4 5 : 2

borland c/cpp think its:
1 2 2 4 5 : 2
1 2 2 4 5 : 2

msvs 6.0 and 2k5 compiled in C think its:
1 2 3 4 5 : 2
1 2 2 4 5 : 2

msvs 6.0 and 2k5 compiled in c++ think its:
1 2 2 4 5 : 2
1 2 2 4 5 : 2
 
You're not crazy, it's like that on purpose (see "2)"): http://groups.google.com/group/comp...ent+differences&rnum=9&hl=en#2da9809d01b1e0b7

The VC++ 6.0 compiler gives the exact same results as VS2005 in both cases. I never knew about that difference before. At least MS is being consistent about it. ;)

Code:
VC++ 6.0 compiler w/source as test.c
1 2 3 4 5 : 2
1 2 2 4 5 : 2

VC++ 6.0 compiler w/source as test.cpp
1 2 2 4 5 : 2
1 2 2 4 5 : 2
edit: oops, I didn't see you ran VC++ 6.0 above. I would prefer not to use code like that since it's too inconsistent.
 
The alternative is much looonger though ;o)

Seems pretty clear to me anyhow, but I can understand why the compiler doesnt like it. I will likely need to add code into that loop in the near future so it will wont matter in the future. (That and gcc handles it the way I want it to and it will be running on solaris, so either way.) Chaulk one more thing up as "undefined behavior" I suppose.
 
Lord of Shadows said:
The alternative is much looonger though ;o)
It doesn't have to be. With just 1 extra variable declaration and one extra line of code for each affected variable, you can force consistent behavior.

use (for consistent MS C++/Borland like behavior)
j = (1) ? list[index++] : -1;
list[index] = j;

or (for consistent gcc/g++ like behavior)
curindex = index;
list[curindex] = (1) ? list[index++] : -1;

instead of
list[index] = (1) ? list[index++] : -1;

and it now has consistent output in VC++ 6.0, VS2005, gcc/g++ and BC5.5. ;)
 
In the Project Settings, you can set the switch to make it "Compile as C Code" rather than C++. That should fix it, hopefully though it seems you've just adapted your code instead, which works equally as well.
 
It's not now that I'm thinking in terms of reality. I simply was making wild assumptions about when the post increment was taking place.

Edit: nm prev edit, I gets it ;o)
 
In this case, reality is kind of a relief, isn't it?

I think you can write something a little more readable that works right without too much trouble.
 
I know the C standard leaves certain aspects of expression evaluation undefined - if this isn't one of those cases, it's similar to ones that can bite you in the ass. On top of that, writing it out as 4 lines instead of 2 is going to be more readable anyways. If you want to show off how clever you can be, you might as well be a man about it and use assembly.


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” – Brian W. Kernighan
 
There were a bunch of those programming quotes on digg a while ago including that one.
http://www.digg.com/programming/Programming_Quotes

And it's not that I'm trying to be clever by obfuscating my code, but rather that it's easier (for me at least) to digest this

Code:
for (i = 0, j = 0; i < leftLength && j < rightLength;)
	list[i + j] = (left[i] < right[j]) ? left[i++] : right[j++];
than this
Code:
	for (i = 0, j = 0; i < leftLength && j < rightLength;)
	{
		if (left[i] < right[j])
		{
			list[i + j] = left[i];
			i++;
		}
		else
		{
			list[i + j] = right[j];
			j++;
		}
	}
Assuming that it would work ;o)
 
Lord of Shadows said:
but rather that it's easier (for me at least) to digest this
Why? Because you don't know the first one isn't correct? Or because of some other reason?
 
You see the assignment first with the ternary operator, so its more specific that merely making any decision based on the comparison.
 
That seems like something you could fix by using a comment. Or two.
 
drizzt81 said:
I think the latter is easier to understand, but I am a n00b anyway.

That's how I feel too, though I have used the ternary operator for many things. It's useful for something relatively short and sweet, like:

Code:
// a and b are ints
int c = a > b ? a : b;

Since that is shorter than the if-then-else code block. But for longer things, the ternary operator really does seem like it was invented purely as a means for obfuscation.
 
Back
Top