compile order ms vs c++

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

wgarvin
Posts: 838
Joined: Thu Jul 05, 2007 5:03 pm
Location: British Columbia, Canada

Re: compile order ms vs c++

Post by wgarvin »

Bo Persson wrote:In this particular case, the VC compiler has a "whole program optimization" mode, where it actually CAN see constants defined in another module. The compilation is finalized AFTER the linker has collected all modules in the program!
Even in this case, it does not matter what order you compile them in. Whole program optimization, does not change the semantics of the language at all.

Very few compiler optimizations have any effect on semantics. The only ones I can think of right at the moment are the "assume no aliasing of certain kinds" optimizations.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: compile order ms vs c++

Post by Desperado »

First of all: my "english-power" is not so good, so it is absolutely
possible that i dont use the right expression in some cases which may lead
to misunderstandings.(like compiler state...).
if anyone of you gets the impression, that there is such a situation,pls ask
once, before we discuss, only because i dont know the english language perfectly.


1.PERSONAL REPLIES
==========================================================

- HI ALEKS: of course there is no compiler state(just ment what the compiler knows
for the moment it runs) thx for reply.
- HI WYLIE: i fully agree with you.

- Hi HARALD: i am never bored or angry in reading comments of experienced programmers.
Also i like to mention that my pseudo-code was very unluckily.
Finally it has nothing to do with the problem i describe in point 2.

Constants are regularly put to headers, and they have to be defined.
So in this view definitions are a natural part of headers.

including operations must not be sequentiell operations.Especially where
include-fileS are interleaving and my produce loops and similar stuff.
include-files are including also includes which may cause unwanted redefinitions
or whatever...So it is not unusual to put defines around includes to avoid
multiple including-operations.There are a lot more reasons to "protect"
an include-advice.

Pls dont conclude on any experience anyone of the programmers have.
Everyones knowledge leaks in some situations,unfortunately in this
case at a very basic point.But if you read point2 carefully, you will
recognize i just leaved the "straight-on" road for just a moment.
With a plausibel idea, which was a wrong idea.Thats all and has nothing
to do with any experience,although i enforced your impression by the
frazzle of pseudocode. This is just a wrong conclusion, with most
respect to you.


- Hi BO: i also fully agree with your post.Sometimes when thinking around a trivial problem
i get a little bit confused after a while. I think anyone of you know that.

- Hi Marco: received your post at the moment. You are absolutely right!


2.THE CONFUSED IDEA WAS...
(NOT IN MIND ANY TRICKY CODE OR ANY OPTIMIZATION!)
==========================================================

STATEMENT1: "extern const type c_name = value;"
STATEMENT2: "extern const type c_name;"

The only thing i tried was absolut natural idea, i just wanted to share a "GLOBAL CONSTANT"
like everyone does with variables through putting it to a header.
For some reason i thought i dont need STATEMENT1 multiple times, it would be enough to have STATEMENT2.
I thought STATEMENT1 has to occur only one time anywhere in the project.

" And i must accept that this is simply wrong "

The STATEMENT2 simply leaks because it is a "dependent" statement,
of what the compiler knows for the moment.(Thats the mistake, not more or less).

(Discussing how to handle headers by just having a frazzle of pseudocode doesnt make much sense to me.Although i must admit, that it(pseudocode) wasnt rich in its contents and looked very poor
Moreover it has absolut no effect on the problem i described in this point.
The only question was, if STATEMENT2 works or not, it works but not
propper, so i will forget it, and i have learned some more basics)

(a little more suprise to me, that none of you ever tried such a statement within years of programming. You all know MURPHY LAW :-), what you can do wrong you will do wrong. Now me was just one more victim :-))

3.PRINCIPAL SOLUTION
==========================================================

It is very easy, last but not least, to get a propper source, i have to have the definitions for a
constant at hand (no way around).To make that sure it is necessay to make STATEMENT1 available
for a modul(directly put in, or having header including this), to avoid dependencies.

This was my final post on this topic, thx again for all comments, although
i wasnt able to tell you what i meant correctly at first,
although the confusing pseudocode,
although the thread had nothing to do with chessprogramming(especially for that!!)

You are all welcome on my next thread. :D
User avatar
Bo Persson
Posts: 243
Joined: Sat Mar 11, 2006 8:31 am
Location: Malmö, Sweden
Full name: Bo Persson

Re: compile order ms vs c++

Post by Bo Persson »

Desperado wrote:
2.THE CONFUSED IDEA WAS...
(NOT IN MIND ANY TRICKY CODE OR ANY OPTIMIZATION!)
==========================================================

STATEMENT1: "extern const type c_name = value;"
STATEMENT2: "extern const type c_name;"

The only thing i tried was absolut natural idea, i just wanted to share a "GLOBAL CONSTANT"
like everyone does with variables through putting it to a header.
For some reason i thought i dont need STATEMENT1 multiple times, it would be enough to have STATEMENT2.
I thought STATEMENT1 has to occur only one time anywhere in the project.

" And i must accept that this is simply wrong "
No, it is not wrong at all - just complicated for no good reason. :-)

Ok, it is a bit confused, in that you can have as many STATEMENT2 as you like, but exactly one STATEMENT1.

Also, this is the C way of defining a global constant. But as you seem to write in C++ (a totally different language!), you can use the feature of having

const type c_name = value;

in every compilation unit. Note that there is no 'extern' here! In C++ const values default to being static, the opposite of extern.
User avatar
Onno Garms
Posts: 224
Joined: Mon Mar 12, 2007 7:31 pm
Location: Bonn, Germany

Re: compile order ms vs c++

Post by Onno Garms »

Hi Harald,

I highly agree on all points of your post apart from this one:
Harald wrote: - Every module (*.h header file or *.c, *.cpp implementation file) should
include the declarations of everything it needs,
You should include as few headers as possible from other headers. That means, if compoent.h needs to know that Something is a class, do not #include something.h, but make a forward declaration of Something. In most cases you will have to #include something.h from component.cpp then.

The reason is that if othercomponent.cpp needs to include component.h, othercomponent doesn't need to be recompiled when something.h is modified.

Apart from this exception of course you should include everything you need.
User avatar
Onno Garms
Posts: 224
Joined: Mon Mar 12, 2007 7:31 pm
Location: Bonn, Germany

Re: compile order ms vs c++

Post by Onno Garms »

Onno Garms wrote:The standard way to solve solve your problems might be to rewrite piece.h as follows:

Code: Select all

#ifndef PIECE_DEC
#define PIECE_DEC

enum { wp=1, wn=2 };

#endif
Another way is

Code: Select all

#ifndef PIECE_DEC
#define PIECE_DEC

class Piece
{
public:
  static const UI_08 wp = 1;
};

#endif
This makes the const values visible to all modules and allocates memory for them only once for all modules. Unlinke enum this also works for UI_64.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: compile order ms vs c++

Post by Sven »

Onno Garms wrote:
Onno Garms wrote:The standard way to solve solve your problems might be to rewrite piece.h as follows:

Code: Select all

#ifndef PIECE_DEC
#define PIECE_DEC

enum { wp=1, wn=2 };

#endif
Another way is

Code: Select all

#ifndef PIECE_DEC
#define PIECE_DEC

class Piece
{
public:
  static const UI_08 wp = 1;
};

#endif
This makes the const values visible to all modules and allocates memory for them only once for all modules. Unlinke enum this also works for UI_64.
If you want to use "++" operations without defining extra type-safe "operator++" then the following mixture might be a good compromise:

Code: Select all

class Piece
{
public:
    enum { wp=1, wn=2, wb=3, wr=4, wq=5, wk=6 };
    void someMethod();
};

void Piece::someMethod() {
    for &#40;int p=wp; p<=wk; p++) &#123; ... &#125;
&#125;

void someGlobalFunction&#40;) &#123;
    for &#40;int p=Piece&#58;&#58;wp; p<=Piece&#58;&#58;wk; p++) &#123; ... &#125;
&#125;
Instead, Tord for instance defines some additional "operator++" for some enumeration types (which are named in contrast to this example), avoids mixing int and enum, and remains fully type-safe. It may be a matter of personal style whether you like having the additional operators, but for me it looks like a clean way of doing it, as soon as you understand how it works.

A small drawback may be that keeping the enum type within the class scope would make the source code that uses that type slightly longer, so that one would be tempted to make the enum type global again, with the disadvantage of possible name clashes within the global name space.

Sven
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

C++ classes for enumeration scalars

Post by sje »

C++ classes for enumeration scalars are, IMHO, generally unneeded.

Here's a code excerpt from Symbolic that defines a few enumeration types and functions.

Note: Type safety everywhere.

Note: BX(n) in a preprocessor function definition for (1 << N)

Code: Select all

// Color

typedef enum
&#123;
  ColorNil = -1,
  ColorWhite, ColorBlack, ColorVacant, ColorExtra
&#125; Color;

#define ColorLen   &#40;ColorExtra + 1&#41;
#define ColorRCLen &#40;ColorBlack + 1&#41;

inline void DecrColor&#40;Color& color&#41; &#123;color = &#40;Color&#41; &#40;color - 1&#41;;&#125;
inline void IncrColor&#40;Color& color&#41; &#123;color = &#40;Color&#41; &#40;color + 1&#41;;&#125;

inline bool IsColorNil&#40;const Color color&#41;    &#123;return color <  0;&#125;
inline bool IsColorNotNil&#40;const Color color&#41; &#123;return color >= 0;&#125;

inline bool IsColorWhite&#40;const Color color&#41;  &#123;return color == ColorWhite;&#125;
inline bool IsColorBlack&#40;const Color color&#41;  &#123;return color == ColorBlack;&#125;
inline bool IsColorVacant&#40;const Color color&#41; &#123;return color == ColorVacant;&#125;

inline Color OtherColor&#40;const Color color&#41; &#123;return &#40;Color&#41; &#40;color ^ 0x01&#41;;&#125;

inline void FlipColor&#40;Color& color&#41; &#123;color = OtherColor&#40;color&#41;;&#125;

// Piece

typedef enum
&#123;
  PieceNil = -1,
  PiecePawn, PieceKnight, PieceBishop, PieceRook, PieceQueen, PieceKing,
  PieceVacant, PieceExtra
&#125; Piece;

#define PieceLen   &#40;PieceExtra + 1&#41;
#define PieceRCLen &#40;PieceKing  + 1&#41;

inline void DecrPiece&#40;Piece& piece&#41; &#123;piece = &#40;Piece&#41; &#40;piece - 1&#41;;&#125;
inline void IncrPiece&#40;Piece& piece&#41; &#123;piece = &#40;Piece&#41; &#40;piece + 1&#41;;&#125;

inline bool IsPieceNil&#40;const Piece piece&#41;    &#123;return piece <  0;&#125;
inline bool IsPieceNotNil&#40;const Piece piece&#41; &#123;return piece >= 0;&#125;

// Man

typedef enum
&#123;
  ManNil = -1,
  ManWhitePawn, ManWhiteKnight, ManWhiteBishop, ManWhiteRook, ManWhiteQueen, ManWhiteKing,
  ManBlackPawn, ManBlackKnight, ManBlackBishop, ManBlackRook, ManBlackQueen, ManBlackKing,
  ManVacant, ManExtra
&#125; Man;

#define ManLen   &#40;ManExtra     + 1&#41;
#define ManRCLen &#40;ManBlackKing + 1&#41;

inline void DecrMan&#40;Man& man&#41; &#123;man = &#40;Man&#41; &#40;man - 1&#41;;&#125;
inline void IncrMan&#40;Man& man&#41; &#123;man = &#40;Man&#41; &#40;man + 1&#41;;&#125;

inline bool IsManNil&#40;const Man man&#41;       &#123;return man <  0;&#125;
inline bool IsManNotNil&#40;const Man man&#41;    &#123;return man >= 0;&#125;

inline bool IsManVacant&#40;const Man man&#41;    &#123;return man == ManVacant;&#125;
inline bool IsManNotVacant&#40;const Man man&#41; &#123;return man != ManVacant;&#125;

inline bool IsManWhite&#40;const Man man&#41;     &#123;return 0x003f & BX&#40;man&#41;;&#125;
inline bool IsManBlack&#40;const Man man&#41;     &#123;return 0x0fc0 & BX&#40;man&#41;;&#125;

inline bool IsManPawn&#40;const Man man&#41;      &#123;return 0x0041 & BX&#40;man&#41;;&#125;
inline bool IsManKnight&#40;const Man man&#41;    &#123;return 0x0082 & BX&#40;man&#41;;&#125;
inline bool IsManBishop&#40;const Man man&#41;    &#123;return 0x0104 & BX&#40;man&#41;;&#125;
inline bool IsManRook&#40;const Man man&#41;      &#123;return 0x0208 & BX&#40;man&#41;;&#125;
inline bool IsManQueen&#40;const Man man&#41;     &#123;return 0x0410 & BX&#40;man&#41;;&#125;
inline bool IsManKing&#40;const Man man&#41;      &#123;return 0x0820 & BX&#40;man&#41;;&#125;

inline bool IsManKQB&#40;const Man man&#41;       &#123;return 0x0d34 & BX&#40;man&#41;;&#125;
inline bool IsManKQBP&#40;const Man man&#41;      &#123;return 0x0d75 & BX&#40;man&#41;;&#125;
inline bool IsManKQR&#40;const Man man&#41;       &#123;return 0x0e38 & BX&#40;man&#41;;&#125;
inline bool IsManKQRBN&#40;const Man man&#41;     &#123;return 0x0fbe & BX&#40;man&#41;;&#125;
inline bool IsManQB&#40;const Man man&#41;        &#123;return 0x0514 & BX&#40;man&#41;;&#125;
inline bool IsManQR&#40;const Man man&#41;        &#123;return 0x0618 & BX&#40;man&#41;;&#125;
inline bool IsManQRBN&#40;const Man man&#41;      &#123;return 0x079e & BX&#40;man&#41;;&#125;

inline bool IsManStepper&#40;const Man man&#41;   &#123;return 0x08e3 & BX&#40;man&#41;;&#125;
inline bool IsManSweeper&#40;const Man man&#41;   &#123;return 0x071c & BX&#40;man&#41;;&#125;

inline Man OtherPawn&#40;const Man man&#41;   &#123;return &#40;Man&#41; (&#40;ManWhitePawn   + ManBlackPawn&#41;   - man&#41;;&#125;
inline Man OtherKnight&#40;const Man man&#41; &#123;return &#40;Man&#41; (&#40;ManWhiteKnight + ManBlackKnight&#41; - man&#41;;&#125;
inline Man OtherBishop&#40;const Man man&#41; &#123;return &#40;Man&#41; (&#40;ManWhiteBishop + ManBlackBishop&#41; - man&#41;;&#125;
inline Man OtherRook&#40;const Man man&#41;   &#123;return &#40;Man&#41; (&#40;ManWhiteRook   + ManBlackRook&#41;   - man&#41;;&#125;
inline Man OtherQueen&#40;const Man man&#41;  &#123;return &#40;Man&#41; (&#40;ManWhiteQueen  + ManBlackQueen&#41;  - man&#41;;&#125;
inline Man OtherKing&#40;const Man man&#41;   &#123;return &#40;Man&#41; (&#40;ManWhiteKing   + ManBlackKing&#41;   - man&#41;;&#125;

inline Man MapColorToPawn&#40;const Color color&#41;   &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PiecePawn&#41;  ;&#125;
inline Man MapColorToKnight&#40;const Color color&#41; &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PieceKnight&#41;;&#125;
inline Man MapColorToBishop&#40;const Color color&#41; &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PieceBishop&#41;;&#125;
inline Man MapColorToRook&#40;const Color color&#41;   &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PieceRook&#41;  ;&#125;
inline Man MapColorToQueen&#40;const Color color&#41;  &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PieceQueen&#41; ;&#125;
inline Man MapColorToKing&#40;const Color color&#41;   &#123;return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + PieceKing&#41;  ;&#125;

inline Man MapColorPieceToMan&#40;const Color color, const Piece piece&#41;
&#123;
  return &#40;Man&#41; (&#40;color * PieceRCLen&#41; + piece&#41;;
&#125;
User avatar
Onno Garms
Posts: 224
Joined: Mon Mar 12, 2007 7:31 pm
Location: Bonn, Germany

Re: C++ classes for enumeration scalars

Post by Onno Garms »

sje wrote:C++ classes for enumeration scalars are, IMHO, generally unneeded.
First, I have classes anyway for reasons that would lead away from the OP questions.

Second, how do you implement the following without classes?
- 64 bit constants e.g. bitboards with one bit set
- for a compiler that does not know 64 bit enums (e.g. M$, even the 64 bit edition)
- definition of constants visible from every file (to allow inlining of their values and their use in switch statements)
- without having one instance of (static) variables in every object file
- without "multibly defined symbol" linker errors
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: C++ classes for enumeration scalars

Post by sje »

Onno Garms wrote:
sje wrote:C++ classes for enumeration scalars are, IMHO, generally unneeded.
First, I have classes anyway for reasons that would lead away from the OP questions.

Second, how do you implement the following without classes?
- 64 bit constants e.g. bitboards with one bit set
- for a compiler that does not know 64 bit enums (e.g. M$, even the 64 bit edition)
- definition of constants visible from every file (to allow inlining of their values and their use in switch statements)
- without having one instance of (static) variables in every object file
- without "multibly defined symbol" linker errors
First, bitboards do not form a typical enumeration type.

#define ConstantSingleBitBB(sq) BB(1 << sq) // Or use constant value static class variables

I don't need compiler support for 64 enumeration values.

Header files contain all the enumeration type definitions, so every one sees the same values. Duplicate storage is not a problem because the type definitions are just that: type definitions and so have no storage requirements as by themselves do not create any objects.

Global variables, if any, can be stashed away as static member variables in a single instanced class.

It just isn't necessary to have any enumeration constant to be realized as an allocated and initialized object, no more than it's necessary for the run time support to store the explicit values for "true" or "false".
User avatar
Onno Garms
Posts: 224
Joined: Mon Mar 12, 2007 7:31 pm
Location: Bonn, Germany

Re: C++ classes for enumeration scalars

Post by Onno Garms »

sje wrote: First, bitboards do not form a typical enumeration type.
I don't need compiler support for 64 enumeration values.
I like typesafe bitboards and I don't know another way then a 64 bit enum to implement that. But that may be a matter of personal taste.
#define ConstantSingleBitBB(sq) BB(1 << sq) // Or use constant value static class variables
That are your two options to define bitboards when you don't have 64 bit enums.

Let me reformulate my previous post: Provided that you don't want to use the preprocessor for that (for me the preprocessor is always the last option, so I did not think of that) and that you don't have 64 bit enums, the only way to define 64 bit constants is to use constant value static class variables. Other solutions have severe drawbacks:

1. Put extern const variables in bitboard.hpp and the definition in bitboard.cpp: Not good, compiler cannot inline the value.

2. Put static const variables in bitboard.hpp: The relatively best solution. But puts instances of the constants in every module, so wastes memory.

3. Put extern const variables in bitboard.hpp: Results in multiply defined symbols.
Header files contain all the enumeration type definitions, so every one sees the same values. Duplicate storage is not a problem because the type definitions are just that: type definitions and so have no storage requirements as by themselves do not create any objects.

Global variables, if any, can be stashed away as static member variables in a single instanced class.

It just isn't necessary to have any enumeration constant to be realized as an allocated and initialized object, no more than it's necessary for the run time support to store the explicit values for "true" or "false".
Everything true, but not related to what my post was intended to express.