I seem to occasionally have problems where different compilation units "see"
different versions of a class definition, either due to inconsistent
settings and preprocessor macros or differing source files. Although this
does not occur frequently, when it does occur it is hard for me to tell
which classes and files are affected. Does anyone have any tips for
debugging this situation, or forcing link-time errors when it does occur?
--
KCS
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Kevin
|
1/13/2004 10:12:06 AM |
|
In message <HrE866.IDt@news.boeing.com>, Kevin Saff
<google.com@kevin.saff.net> writes
>I seem to occasionally have problems where different compilation units "see"
>different versions of a class definition, either due to inconsistent
>settings and preprocessor macros or differing source files. Although this
>does not occur frequently, when it does occur it is hard for me to tell
>which classes and files are affected. Does anyone have any tips for
>debugging this situation, or forcing link-time errors when it does occur?
Well the first issue is that there should only be one piece of source
code that implements a class definition (a .cpp file). There should also
be only one file with the class definition in it (a suitable header
file).
The next issue is to ensure that the implementation file compiles
correctly but does not include any headers that it does not need.
Third, have a system for ordering the inclusion of header files. I
include user provided headers first (in alphabetical order) and Standard
Library headers afterwards (in alphabetical order). This does not
guarantee that header files do not interact but at least it makes it
more likely that they do so the same way.
Fourth, always use a version control system.
Fifth, regularly rebuild your project; that makes it more likely that
you will use the same compiler switches for all TUs.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
1/13/2004 3:06:31 PM
|
|
"Kevin Saff" <google.com@kevin.saff.net> wrote in message news:<HrE866.IDt@news.boeing.com>...
> I seem to occasionally have problems where different compilation units "see"
> different versions of a class definition, either due to inconsistent
> settings and preprocessor macros or differing source files. Although this
> does not occur frequently, when it does occur it is hard for me to tell
> which classes and files are affected. Does anyone have any tips for
> debugging this situation, or forcing link-time errors when it does occur?
I've had the same problem many times, but only when working with 3rd
party libraries (especially MFC) which is full of #define's that
change the sizes of objects (e.g. Debug and Release mode objects are
often different sizes). I (almost) never use #define's in own my
code, so I've never had the problem there. As far as compiler
settings, I assume you mean things like struct-packing rules etc. - in
which case, just make sure you never change the default (at least in a
compiler setting - if you really really need it, use a #pragma).
But I sympathize, it took me a good 4 hours to track down a problem
like this where I could see a variable getting set from one source
file, but getting read with a different value (and from a different
address) in another. I would've thought a good compiler could check
for this sort of thing, but I'm not aware of any that do.
Dylan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
wizofaus
|
1/14/2004 10:23:41 AM
|
|
Hi!
Francis Glassborow wrote:
> Third, have a system for ordering the inclusion of header files. I
> include user provided headers first (in alphabetical order) and Standard
> Library headers afterwards (in alphabetical order).
I do it the other way: include standard headers first, library headers
second (boost, or something), own headers last.
This way I try to avoid the problem, that the user defined headers do
"bad" stuff which would affect the standard things (like a misnamed
#define or anything else).
Additionally I can assign the standard headers for a precompiled header
in BCB. The standard headers are unlikely to change a lot, thus the
precompiled header will save compile time.
Frank
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Frank
|
1/14/2004 10:26:48 AM
|
|
In message <bu1urc$cmg2t$2@ID-220067.news.uni-berlin.de>, Frank
Birbacher <bloodymir.crap@gmx.net> writes
>Francis Glassborow wrote:
> > Third, have a system for ordering the inclusion of header files. I
> > include user provided headers first (in alphabetical order) and Standard
> > Library headers afterwards (in alphabetical order).
>
>I do it the other way: include standard headers first, library headers
>second (boost, or something), own headers last.
Having a systematic approach is overwhelmingly the most important IMO.
>
>This way I try to avoid the problem, that the user defined headers do
>"bad" stuff which would affect the standard things (like a misnamed
>#define or anything else).
If a user defined header contains such bad stuff I want to eliminate it
as soon as possible because it has the potential for nasty interactions
with subsequently included user defined headers.
In addition, I do not want my user defined headers to just happen to
work because the environments in which they have been tested happen to
pre-include a standard header that they depended on.
That is not to say that your ordering lacks merit. As I said above, an
ordering is the most important feature.
>
>Additionally I can assign the standard headers for a precompiled header
>in BCB. The standard headers are unlikely to change a lot, thus the
>precompiled header will save compile time.
A good point, however it would be 'nicer' if implementations allowed
users to specify which headers to precompile rather than requiring a
specific ordering.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
1/14/2004 2:16:13 PM
|
|
In message <7d428a77.0401131153.14d7fd42@posting.google.com>, Dylan
Nicholson <wizofaus@hotmail.com> writes
>As far as compiler
>settings, I assume you mean things like struct-packing rules etc. - in
>which case, just make sure you never change the default (at least in a
>compiler setting - if you really really need it, use a #pragma).
>But I sympathize, it took me a good 4 hours to track down a problem
>like this where I could see a variable getting set from one source
>file, but getting read with a different value (and from a different
>address) in another. I would've thought a good compiler could check
>for this sort of thing, but I'm not aware of any that do.
A good point, it should not be too hard for a compiler to store the
current state of its switches at the start of an object file and for the
linker to check compatibility between object files. Any compiler
implementor like to comment? This might be even more useful for
dynamically loaded libraries (assuming the executable also stores the
compilers switches).
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
1/14/2004 2:16:35 PM
|
|
"Francis Glassborow" <francis@robinton.demon.co.uk> schrieb im Newsbeitrag
news:4A4$GQBE08AAFw8T@robinton.demon.co.uk...
<snip />
>
> Third, have a system for ordering the inclusion of header files. I
> include user provided headers first (in alphabetical order) and Standard
> Library headers afterwards (in alphabetical order). This does not
> guarantee that header files do not interact but at least it makes it
> more likely that they do so the same way.
>
That's like I do it, except that the first included header in a cpp file is
the
the header file of the cpp file itsself. E.g.:
// file myclass.cpp:
#include "myclass.h"
// project includes:
#include "a.h"
// own library includes:
#include <myutil.h>
// foreign library include
#include <boost/lexical_cast.hpp>
// std library includes
#include <vector>
// end myclass.cpp
This way I force my headers to be stand alone compilable. Of course, I
cannot
follow this path for the library includes, that are not compilable on their
own.
Bye
Norbert
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Norbert
|
1/14/2004 10:51:15 PM
|
|
"Dylan Nicholson" <wizofaus@hotmail.com> wrote in message
news:7d428a77.0401131153.14d7fd42@posting.google.com...
> "Kevin Saff" <google.com@kevin.saff.net> wrote in message
news:<HrE866.IDt@news.boeing.com>...
> > I seem to occasionally have problems where different compilation units
"see"
> > different versions of a class definition, either due to inconsistent
> > settings and preprocessor macros or differing source files. Although
this
> > does not occur frequently, when it does occur it is hard for me to tell
> > which classes and files are affected. Does anyone have any tips for
> > debugging this situation, or forcing link-time errors when it does
occur?
>
> I've had the same problem many times, but only when working with 3rd
> party libraries (especially MFC) which is full of #define's that
> change the sizes of objects (e.g. Debug and Release mode objects are
> often different sizes). I (almost) never use #define's in own my
> code, so I've never had the problem there. As far as compiler
> settings, I assume you mean things like struct-packing rules etc. - in
> which case, just make sure you never change the default (at least in a
> compiler setting - if you really really need it, use a #pragma).
> But I sympathize, it took me a good 4 hours to track down a problem
> like this where I could see a variable getting set from one source
> file, but getting read with a different value (and from a different
> address) in another. I would've thought a good compiler could check
> for this sort of thing, but I'm not aware of any that do.
Yes, I am primarily concerned with interaction with 3rd party libraries.
Using MSVC and wxWindows, I had a problem where a couple wxWindows projects
were defining different preprocessor macros, which led to an inconsistent
class that over-wrote a byte or two of a virtual pointer on a different
object. It would be nice if a linker could somehow see that the class had
different sizes in different units and at least issue a warning.
Also, I have occasionally seen different libraries "see" different versions
of STL - this is usually pretty easy to debug, though.
I asked because I am currently tracking down what feels like a similar bug -
a class passes its unit tests but causes a memory access violation when
included in a dialog window. Of course it may be a completely different
problem, but the fact I can't easily test this compatibility I find
distressing.
One intrusive workaround is to check sizes, relying on inlining like:
// foo.h
class Foo
{
static unsigned compiled_size(); // defined in foo.cpp - return sizeof
(Foo);
static unsigned header_size()
{
return sizeof (Foo);
}
static bool check_size_consistency()
{
return compiled_size() == header_size();
}
initialize(); // Foo initialization
public:
Foo()
{
assert (check_size_consistency());
initialize();
}
};
I find this quite ugly for such a thing, though - and it relies on altering
the class, something quite undesirable for 3rd party libraries.
Maybe a less intrusive method could work something like:
// size_checker.h:
class SizeChecker
{
public:
bool check (type_info const& class_to_check_size_of, unsigned size);
template <class T>
SizeChecker (T*)
{
if (!check (typeid (T), sizeof (T)))
throw something;
}
};
// size_checker.cpp:
SizeChecker::check (type_info const& class_to_check_size_of, unsigned size)
{
static std::map <type_info, unsigned> size_map;
if (size_map [class_to_check_size_of] == 0)
size_map [class_to_check_size_of] = size;
return size == size_map [class_to_check_size_of];
}
// foo.h:
#include "size_checker.h"
class Foo
{
// usual Foo stuff
};
namespace {
SizeChecker (Foo*(0)); // forces checking size in every unit that
includes foo.h?
}//namespace{}
Think that might work?
--
KCS
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Kevin
|
1/14/2004 11:03:04 PM
|
|
Francis Glassborow <francis@robinton.demon.co.uk> wrote in message news:<$OEeF3CyKSBAFwVj@robinton.demon.co.uk>...
> In message <7d428a77.0401131153.14d7fd42@posting.google.com>, Dylan
> Nicholson <wizofaus@hotmail.com> writes
> >As far as compiler
> >settings, I assume you mean things like struct-packing rules etc. - in
> >which case, just make sure you never change the default (at least in a
> >compiler setting - if you really really need it, use a #pragma).
> >But I sympathize, it took me a good 4 hours to track down a problem
> >like this where I could see a variable getting set from one source
> >file, but getting read with a different value (and from a different
> >address) in another. I would've thought a good compiler could check
> >for this sort of thing, but I'm not aware of any that do.
>
> A good point, it should not be too hard for a compiler to store the
> current state of its switches at the start of an object file and for the
> linker to check compatibility between object files. Any compiler
> implementor like to comment? This might be even more useful for
> dynamically loaded libraries (assuming the executable also stores the
> compilers switches).
The easiest way to prevent using incompatible types with the same
name is to put debug info into the object files, and to check
in the linker the types used in different object files.
This can be done for dynamic libraries as well. This is one of the cases
when you need debug info WITH optimization in a compiler.
The usual problems of optimization with debug info don't apply
here because you only need the types.
I had never heard this to be actually done, but you can check if
your linker can do this. If it cannot, you can write a small program
that would read the debug info from the objects and issue a warning
for incompatible types. Unfortunately, this program wouldn't be
portable!-)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
tmk
|
1/15/2004 10:14:29 AM
|
|
Hi!
Francis Glassborow wrote:
> Having a systematic approach is overwhelmingly the most important IMO.
Ok. I didn't think about it a lot. My ordering just is natural to me.
> If a user defined header contains such bad stuff I want to eliminate it
> as soon as possible because it has the potential for nasty interactions
> with subsequently included user defined headers.
>
> In addition, I do not want my user defined headers to just happen to
> work because the environments in which they have been tested happen to
> pre-include a standard header that they depended on.
I admit that I sometimes forget to include header which implicitly
already have been included (e.g. #include <sstream> but not <string>,
now you use std::string all over the place).
Well, if a header is missing sometime, you can figure that out fast.
> A good point, however it would be 'nicer' if implementations allowed
> users to specify which headers to precompile rather than requiring a
> specific ordering.
I don't get what you want to say here.
Although we didn't specify it, I was thinking of .cpp files, where I
am the user/writer and choose my headers for precompilation. I don't
specify precompiled headers in any header. Thus your statement doesn't
make sense to me. Please clearify.
Frank
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Frank
|
1/15/2004 10:30:02 AM
|
|
Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
news:<$OEeF3CyKSBAFwVj@robinton.demon.co.uk>...
> In message <7d428a77.0401131153.14d7fd42@posting.google.com>, Dylan
> Nicholson <wizofaus@hotmail.com> writes
> >As far as compiler settings, I assume you mean things like
> >struct-packing rules etc. - in which case, just make sure you never
> >change the default (at least in a compiler setting - if you really
> >really need it, use a #pragma). But I sympathize, it took me a good 4
> >hours to track down a problem like this where I could see a variable
> >getting set from one source file, but getting read with a different
> >value (and from a different address) in another. I would've thought a
> >good compiler could check for this sort of thing, but I'm not aware
> >of any that do.
> A good point, it should not be too hard for a compiler to store the
> current state of its switches at the start of an object file and for
> the linker to check compatibility between object files. Any compiler
> implementor like to comment? This might be even more useful for
> dynamically loaded libraries (assuming the executable also stores the
> compilers switches).
That would be one solution. Another thing that would be useful would be
for the compiler to store a hash of things subject to the one definition
rule in the object file, and for the linker to insist that all
compilations referring to it had the same hash value.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
1/15/2004 3:06:00 PM
|
|
In message <bu4grk$duhd4$1@ID-220067.news.uni-berlin.de>, Frank
Birbacher <bloodymir.crap@gmx.net> writes
> > A good point, however it would be 'nicer' if implementations allowed
> > users to specify which headers to precompile rather than requiring a
> > specific ordering.
>
>I don't get what you want to say here.
> Although we didn't specify it, I was thinking of .cpp files, where I
>am the user/writer and choose my headers for precompilation. I don't
>specify precompiled headers in any header. Thus your statement doesn't
>make sense to me. Please clearify.
Pre-compiled headers are basically what a compiler creates for its own
use so that it can look up names (yes there is a bit more) in context.
If we had a compiler that could merge several pre-compiled pieces (and
issue diagnostics for incompatibilities) we would no longer have the
current common situation where the pre-compiled part was what comes
first.
All I am saying is that the 'pre-compiled header' concept just took the
simplest scenario, relies on the programmer to have a 'constant' initial
bit and leaves all the other possible compilation optimisations alone. I
think we could do better.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
1/15/2004 3:12:05 PM
|
|
kanze@gabi-soft.fr wrote:
> Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
> news:<$OEeF3CyKSBAFwVj@robinton.demon.co.uk>...
<snip>
>> A good point, it should not be too hard for a compiler to store the
>> current state of its switches at the start of an object file and for
>> the linker to check compatibility between object files. Any compiler
>> implementor like to comment? This might be even more useful for
>> dynamically loaded libraries (assuming the executable also stores the
>> compilers switches).
>
> That would be one solution. Another thing that would be useful would be
> for the compiler to store a hash of things subject to the one definition
> rule in the object file, and for the linker to insist that all
> compilations referring to it had the same hash value.
Something like this has actually been implemented in the Linux kernel.
There is an option called "versioned symbols" which adds a hash to
the names of functions that are shared between the main kernel and
loadable modules. The hashes are generated by an external program
called genksyms.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Ben
|
1/16/2004 3:00:40 AM
|
|
|
12 Replies
259 Views
(page loaded in 0.097 seconds)
|