C++ MSVS 2005 Express compiler bug?

Started by
14 comments, last by Mantear 17 years, 1 month ago
Greetings! I've got a real head-scratcher here as to why the compiler (MSVS 2005 Express) is compiling something with no errors. Here's the class:
class TestClass
{
public:
    TestClass(){m_Width = 0;}
    ~TestClass(){}
    unsigned int Width(){ return m_Width; }
    void Width(unsigned int width){ m_Width = width; }

private:
    unsigned int m_Width;
};
I made the following mistake in my code:
TestClass object;
if (object.Width > 0)
{ ... }
else
{ ... }
This code snippet compiled with no errors or warnings! It was failing the check that it was supposed to pass and processing the else statement, causing me to take a closer look at that section when I noticed the missing '()'. Even run-time there was no indication of anything going wrong other than the check failing when it shouldn't have. If I remove either declarations of Width(), it won't compile with the normal expected errors. What's going on here?
Advertisement
Sometimes Visual C++ (I've noticed this in every version) gets into a strange state that only rebuilding the entire project can fix.
....[size="1"]Brent Gunning
I've done several complete rebuilds on two different computers. Same results.
It's correct behvaior, but obviously not what you wanted. What it's actually doing is comparing the function istelf (a pointer to that function) to zero. Depending on the address of the code (which probably is an address like 0x8...), the value (when interpreted as a signed value) is negative, so the else clause is taken.

It's an obnoxious bug that comes up every so often. In many cases, the necessary casting to trigger this problem causes the compiler to emit a warning or error. But in some cases (like this one), the surrounding code is simple enough that it just happens silently.
Quote:It's correct behvaior, but obviously not what you wanted. What it's actually doing is comparing the function istelf (a pointer to that function) to zero.

A valiant attempt, but this is not the case here. Forming a pointer-to-member would be required to compare the function's address to zero, and that requires explicit use of the address-of operator and a slightly different syntax in general.

To the OP, there is more to your problem then you have extracted and shown here.
The following code, identical to yours but for the creation of a main() function to hold the offending code, produces error C3867 (complaining that Width() is missing a function call argument list) as expected:
#include <iostream>class TestClass{public:    TestClass(){m_Width = 0;}    ~TestClass(){}    unsigned int Width(){ return m_Width; }    void Width(unsigned int width){ m_Width = width; }private:    unsigned int m_Width;};int main(){  TestClass object;  if (object.Width > 0)  {    std::cout << "TRUE";  }  else  {    std::cout << "FALSE";  }}


Perhaps you have a macro in scope that is doing something funky? Try to pare down the example further.
1>.\Main.cpp(16) : error C3867: 'TestClass::Width': function call missing argument list; use '&TestClass::Width' to create a pointer to member

That's what my VS2k5 SP1 tells me.
Some compilers sometimes lets you get away with omitting the & to get a function pointer, which might be what you're experiencing.

To make it is hell. To fail is divine.

Entire source code of a test project using VisualC++ 2005 Express Edition (Version 8.0.50727.42)

Header: TestClass.h
class TestClass{public:    TestClass(){m_Width = 10;}    ~TestClass(){}    unsigned int Width(){ return m_Width; }    void Width(unsigned int width){ m_Width = width; }private:    unsigned int m_Width;};


Source: TestClass.cpp
// TestClass.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "TestClass.h"int _tmain(int argc, _TCHAR* argv[]){    TestClass object;    bool success;        if (object.Width > 0)    {        success = true;    }    else    {        success = false;    }    return 0;}


Build results:
------ Build started: Project: TestClass, Configuration: Debug Win32 ------Compiling...stdafx.cppCompiling...TestClass.cppCompiling manifest to resources...Linking...Embedding manifest...Build log was saved at "file://c:\3dEngine\Test\TestClass\TestClass\Debug\BuildLog.htm"TestClass - 0 error(s), 0 warning(s)========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========


Running the program takes it down the
success = false
path.
???
The fact that Zao and I are using SP1 might be the difference -- perhaps an appropriate extension to allow pointer-to-member to be formed without the address-of was removed in SP1. I'm somewhat skeptical of that, however, but I haven't dug up a changelist to see.

You could try going to the project options and disabling language extensions to see if it fails then. Also, what's in stdafx.h or anything included by stdafx.h?
I tried it with Language Extensions disabled (/Za) but nothing changed.

stdafx.h is the default file generated by VS. It's contents are:
// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently, but// are changed infrequently//#pragma once#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers#include <stdio.h>#include <tchar.h>// TODO: reference additional headers your program requires here

How do I go about getting SP1? What are the main improvements with SP1?
It compiles for me :(
No SP1, fresh VS install.
Disabled precompiled header.

Even after I examined generated asembly, I cannot find what it's doing:
//... object has just been constructed (eax=this)0040103E  xor         eax,eax 00401040  je          main+18h (401048h) // else

This topic is closed to new replies.

Advertisement