Tips & tricks

Programming Topics (Computer Chess) and technical aspects as test techniques, book building, program tuning etc

Moderator: Andres Valverde

Tips & tricks

Postby Fermin Serrano » 17 Apr 2008, 12:21

I have been searching for a thread about tips, tricks and coding advises.
Maybe a thread with a sticky would be nice if this thread grows.
I like programming and this kind of things.

My 5 cents:

1) My debug system is around two statements:
Code: Select all
   print_board("<tag>");
   Print("<tag>","printf like format", args.....)


I have lot of this around my code. Say I like to debug passed pawn.
After the code I write:

Code: Select all
   print_board("PASSED_PAWN");
   Print("PASSED_PAWN","There is a passed pawn on the %s square\n",
       strSquare(sq));


When I want to debug something, at the initialization of my program
I switch on or off the tags I want to debug. (default off).
Of course, I #define a DEBUG vars. If don't define, all above
statements are avoided and no code is generated.
Also I have and initialization statemente with a parameter that says
if screen dump, file dump, both or none.

I use this system for doing a trace. Example

Code: Select all
   Print("TRACE","Entrance to search function. Node number %d. Time: %s.\n",nodes,strTime(time));


If you write lots of Print with the TRACE tag, and you switch that tag on you will be able to know how your program works.

2) Also I have a profile system to measure how many time a function take.
When enter a function I call PROFILE_START("myfunc()");
Before returning, PROFILE_STOP("myfunc()");
It run like a stack. When a new profile start statement is called,
it stop previous timers and put it on the stack. When it returns
it put the timer of the stack on. Again, a #define controls if code
is beeing or not generated.
A PRINT_PROFILE would show all info.

3) I use "artistic style" tool. It is nice. I use this command:
Code: Select all
 astyle -a -t4 -T4 -K -L -w -M -m0 -f -p -o -O -X -Z -v *.c *.h


4) When commeting, I do it as follow:
Code: Select all
   /*
      myfunc()
      if (x=y) {
         ...
      }
      ...
      mufun2();  /**/


So when I want to uncomment, I only remove the first line. It is
a faster way than usual, where you need to remove the */ also.

5) I have a stadistical system that works similar to debug system. I
don't need to declare one vars per stats I want. The only thing I
need is to call:
Code: Select all
STAT("<tag>",counter);

i.e.
Code: Select all
STAT("check extension",1);


If the tag does not exits, it create a new counter for that tag,
inicializated to the counter.
Again, I have a #define STATS. Ifndef then no code is created at
compile.
A PRINT_STATS would show all info.

The systems described let me dont need to write #ifdef var in each statemnte, as they are define as void when no #define is declared. :)

I would like to hear about your tips. Specially I would like to know
a good system to make a tree dump, or if you use any trick to access in a faster way to global vars (which for default they are not in cache), coding tips, and so on.....

FS
User avatar
Fermin Serrano
 
Posts: 72
Joined: 10 Apr 2008, 18:20
Location: Madrid (Spain)

Re: Tips & tricks

Postby Ron Murawski » 17 Apr 2008, 18:50

Hi Fermin,

Here's an old C trick I learned a long time ago called the 'D macro'. It saves some typing, makes source code look nicer, and is less error-prone. Here it is:
Code: Select all
#ifdef DEBUG
#   define D(x) x
#else
#   define D(x)
#endif

and now instead of having ugly #if statements in your code and worrying if your #if's and #endif's match...
Code: Select all
#if DEBUG
   printf("debug message");
#endif // DEBUG

You can replace it with:
Code: Select all
D(printf("debug message"));

I always put the closing semicolon after the D macro statement and not inside the parentheses. (It makes it look more like a C statement.)

If DEBUG is undefined, anything inside the parenthesis of 'D' will be deleted by the preprocessor and the "expansion" of the 'D macro' will be nothing at all, followed by the semicolon -- a null statement that the compiler will easily optimize away.

If DEBUG *is* defined, the statement inside the parentheses of 'D' remains in the code, followed by the semicolon.

Ron
User avatar
Ron Murawski
 
Posts: 352
Joined: 26 Sep 2004, 21:50
Location: Schenectady, NY, USA

Re: Tips & tricks

Postby Pradu » 19 Apr 2008, 15:05

Ron Murawski wrote:Hi Fermin,

Here's an old C trick I learned a long time ago called the 'D macro'. It saves some typing, makes source code look nicer, and is less error-prone. Here it is:
Code: Select all
#ifdef DEBUG
#   define D(x) x
#else
#   define D(x)
#endif

and now instead of having ugly #if statements in your code and worrying if your #if's and #endif's match...
Code: Select all
#if DEBUG
   printf("debug message");
#endif // DEBUG

You can replace it with:
Code: Select all
D(printf("debug message"));

I always put the closing semicolon after the D macro statement and not inside the parentheses. (It makes it look more like a C statement.)

If DEBUG is undefined, anything inside the parenthesis of 'D' will be deleted by the preprocessor and the "expansion" of the 'D macro' will be nothing at all, followed by the semicolon -- a null statement that the compiler will easily optimize away.

If DEBUG *is* defined, the statement inside the parentheses of 'D' remains in the code, followed by the semicolon.

Ron
Wow very nice trick. My code is filled with the ugly #ifndef NDEBUG stuff for single line statements.
User avatar
Pradu
 
Posts: 343
Joined: 12 Jan 2005, 19:17
Location: Chandler, Arizona, USA

Re: Tips & tricks

Postby H.G.Muller » 19 Apr 2008, 18:09

I always write

if(DEBUG)

in front of my debug statements, and then, if I am done debugging, set

#define DEBUG 0

and count on the optimizer to delete all unreachable code. When I am debugging, I usually have something like

#define DEBUG level==N && path[1]==MOVE1 && path[2]==MOVE2 ...

to activate the statements in a node where I want to have diagnostic output.
User avatar
H.G.Muller
 
Posts: 3453
Joined: 16 Nov 2005, 12:02
Location: Diemen, NL

Re: Tips & tricks

Postby Ron Murawski » 20 Apr 2008, 17:42

H.G.Muller wrote:I always write

if(DEBUG)

in front of my debug statements...


I once used that technique but, at the highest warning levels, the compiler complains that the quantity inside the if-statement is a constant.

Of course you can suppress that particular warning message or compile at low warning levels, and the warning will disappear.

Ron
User avatar
Ron Murawski
 
Posts: 352
Joined: 26 Sep 2004, 21:50
Location: Schenectady, NY, USA

Re: Tips & tricks

Postby Ron Murawski » 20 Apr 2008, 17:53

Pradu wrote:Wow very nice trick. My code is filled with the ugly #ifndef NDEBUG stuff for single line statements.


Glad you liked the trick! Here's a different trick to find signed/unsigned 8/16/32/64-bit types. It relies on the values in limits.h and some common sense.
Code: Select all
//______________________________________________________________________________
// types.h - find signed and unsigned 8, 16, 32 and 64-bit types
//______________________________________________________________________________

// types are:
//       u8     unsigned  8-bit type
//       s8       signed  8-bit type
//      u16     unsigned 16-bit type
//      s16       signed 16-bit type
//      u32     unsigned 32-bit type
//      s32       signed 32-bit type
//      u64     unsigned 64-bit type
//      s64       signed 64-bit type



#ifndef TYPES_DEFINED
    #define TYPES_DEFINED
    #include <limits.h>

    // ----- find an unsigned 8-bit type -----

    #if UCHAR_MAX == 255U
        typedef unsigned  char u8;
        #define u8MAX 255U
    #else
        #error "TYPES.H: Can't find an unsigned 8-bit type"
    #endif

    // ----- find a signed 8-bit type -----

    #if SCHAR_MAX == 127
        typedef signed  char s8;
        #define s8MAX 127
        #define s8MIN -128
    #else
        #error "TYPES.H: Can't find a signed 8-bit type"
    #endif

    // ----- find an unsigned 16-bit type -----

    #if   USHRT_MAX == 65535U
        typedef unsigned short u16;
        #define u16MAX 65535U
    #elif UINT_MAX  == 65535U
        typedef unsigned   int u16;
        #define u16MAX 65535U
    #elif ULONG_MAX == 65535UL
        typedef unsigned  long u16;
        #define u16MAX 65535UL
    #else
        #error "TYPES.H: Can't find an unsigned 16-bit type"
    #endif

    // ----- find a signed 16-bit type -----

    #if    SHRT_MAX == 32767
        typedef short s16;
        #define s16MAX 32767
    #elif  INT_MAX  == 32767
        typedef int s16;
        #define s16MAX 32767
    #elif  LONG_MAX == 32767
        typedef long s16;
        #define s16MAX 32767
    #else
        #error "TYPES.H: Can't find a signed 16-bit type"
    #endif

    // ----- find an unsigned 32-bit type -----

    #if   UINT_MAX  == 4294967295U
        typedef unsigned   int u32;
        #define u32MAX 4294967295U
    #elif ULONG_MAX == 4294967295UL
        typedef unsigned  long u32;
        #define u32MAX 4294967295UL
    #else
        #error "TYPES.H: Can't find an unsigned 32-bit type"
    #endif

    // ----- find a signed 32-bit type -----

    #if   INT_MAX  == 2147483647
        typedef int s32;
        #define s32MAX 2147483647
    #elif LONG_MAX == 2147483647L
        typedef long s32;
        #define s32MAX 2147483647L
    #else
        #error "TYPES.H: Can't find a signed 32-bit type"
    #endif

    // ----- find signed and unsigned 64-bit types -----

    // there must be a better way to do this one!
    #ifdef _MSC_VER
        #define u64 unsigned __int64
        #define longlong __int64
        #define s64          __int64
    #else
        #define u64 unsigned long long int
        #define longlong unsigned long long
        #define s64          long long int
    #endif

#endif


Ron
User avatar
Ron Murawski
 
Posts: 352
Joined: 26 Sep 2004, 21:50
Location: Schenectady, NY, USA

Re: Tips & tricks

Postby Ilari Pihlajisto » 20 Apr 2008, 19:56

No trickery is needed. Here's what I do:

Code: Select all
#ifdef _MSC_VER
  typedef __int8 int8_t;
  typedef unsigned __int8 uint8_t;
  typedef __int16 int16_t;
  typedef unsigned __int16 uint16_t;
  typedef __int32 int32_t;
  typedef unsigned __int32 uint32_t;
  typedef __int64 int64_t;
  typedef unsigned __int64 uint64_t;
#else
  #include <inttypes.h>
#endif
User avatar
Ilari Pihlajisto
 
Posts: 78
Joined: 18 Jul 2005, 06:58

Re: Tips & tricks

Postby Zach Wegner » 22 Apr 2008, 04:48

Ron Murawski wrote:
Code: Select all
D(printf("debug message"));

I always put the closing semicolon after the D macro statement and not inside the parentheses. (It makes it look more like a C statement.)


The other reason is to avoid subtle bugs like this:
Code: Select all
if (some_error)
    D(printf("something's screwed up...");)
some_function();

With debug defined, everything is fine. Without it, the some_function() call is suddenly inside an if-block.

For my own contribution to the thread, I will just tell about the PGN system I have in place, as I believe it makes it very efficient as well as modular. In my old engine from years back, I had a separate PGN parser for reading games, creating opening books, and others for anything else like autotuning. Other engines, at least Crafty, do that same thing. Now what I have is a generic system involving function pointers, where I define the type PGN_FUNC:
Code: Select all
typedef BOOL (*PGN_FUNC)(void *pgn_arg, PGN_GAME *pgn_game);
It is called at every move in the parsing stage. It has access to the players and who won and everything from pgn_game, and I have a void pointer for any argument. For example, in the book creating function, I pass in a struct with the buffer to be updated, the size of the buffer, and how deep the book will be. It returns true or false based on whether the PGN reader should stop parsing. I can also just pass in a null pointer for the function, and the PGN is simply read into the board state.
User avatar
Zach Wegner
 
Posts: 182
Joined: 26 Sep 2004, 22:02
Location: Austin, Texas, USA

Re: Tips & tricks

Postby Ron Murawski » 23 Apr 2008, 00:33

Ilari Pihlajisto wrote:No trickery is needed. Here's what I do:

Code: Select all
#ifdef _MSC_VER
  typedef __int8 int8_t;
  typedef unsigned __int8 uint8_t;
  typedef __int16 int16_t;
  typedef unsigned __int16 uint16_t;
  typedef __int32 int32_t;
  typedef unsigned __int32 uint32_t;
  typedef __int64 int64_t;
  typedef unsigned __int64 uint64_t;
#else
  #include <inttypes.h>
#endif


Hi Ilari,

What you have is fine for the Microsoft compiler, but I use several other compilers as well (Digital Mars, Watcom, and GCC). My code works across different compilers as well as different operating systems.

My method is not really "trickery" it's based on the limits.h file that is part of the standard C library. As long as a compiler's number types are represented in a straightforward manner -- and every C compiler I've ever worked with has done so -- you should get the right-sized types or, if it is unimplemented, you will get a compile-time error.

Ron
User avatar
Ron Murawski
 
Posts: 352
Joined: 26 Sep 2004, 21:50
Location: Schenectady, NY, USA

Re: Tips & tricks

Postby Tord Romstad » 23 Apr 2008, 08:09

I don't have a lot of tricks, but here is some general chess programming advice:
  • Use some sort of version control system! What VCS you use is largely a matter of taste (except I would recommend a modern distributed VCS like Darcs, git or Mercury rather than an old-fashioned centralized VCS like Subversion or CVS), but you should definitely use one.
  • Never try to do something difficult! C and C++ are very low-level languages, and using them to do something difficult is asking for trouble. When you are faced with some difficult problem, leave your computer, sit down with pencil and paper in your favorite park or café, and work out how to decompose the difficult problem into tiny and trivial sub-problems. Afterwards, go home and code your solutions to these trivial sub-problems. This approach gives you much clearer and less buggy code than if you just try to attack the difficult problems head-on, and saves you a lot of time in the long run. An additional advantage is that you get a chance to be away from your computer for a while.
  • A related point: Don't debug! If your code doesn't work, and it isn't easy to see precisely what is wrong, it's a sure sign that it is too complex. Discard the old code and replace it with something simpler and clearer.


My "most wanted trick": Is there any way to detect at compile-time whether you are running on a 32-bit or 64-bit CPU?

Tord
User avatar
Tord Romstad
 
Posts: 639
Joined: 09 Oct 2004, 12:49
Location: Oslo, Norway

Re: Tips & tricks

Postby Ilari Pihlajisto » 23 Apr 2008, 12:15

Ron Murawski wrote:Hi Ilari,

What you have is fine for the Microsoft compiler, but I use several other compilers as well (Digital Mars, Watcom, and GCC). My code works across different compilers as well as different operating systems.


My code should work with any C compiler that isn't stuck in the past (inttypes.h is a C99 header). I don't know about Digital Mars or Watcom, but it works fine with GCC.
User avatar
Ilari Pihlajisto
 
Posts: 78
Joined: 18 Jul 2005, 06:58

Re: Tips & tricks

Postby Ilari Pihlajisto » 23 Apr 2008, 12:32

Tord Romstad wrote:My "most wanted trick": Is there any way to detect at compile-time whether you are running on a 32-bit or 64-bit CPU?
Tord


I don't know of anything that will work on every platform, but this seems to cover a lot of them:
Code: Select all
#if defined(__LP64__) || defined(__powerpc64__) || defined(__64BIT__) || defined(_WIN64)
  #define _64_BIT
#else
  #define _32_BIT
#endif
User avatar
Ilari Pihlajisto
 
Posts: 78
Joined: 18 Jul 2005, 06:58

Re: Tips & tricks

Postby Ron Murawski » 23 Apr 2008, 16:57

Ilari Pihlajisto wrote:
Ron Murawski wrote:Hi Ilari,

What you have is fine for the Microsoft compiler, but I use several other compilers as well (Digital Mars, Watcom, and GCC). My code works across different compilers as well as different operating systems.


My code should work with any C compiler that isn't stuck in the past (inttypes.h is a C99 header). I don't know about Digital Mars or Watcom, but it works fine with GCC.


Hi Ilari,

You are right! I was not aware of the C99 changes. I wrote my header file a long, long time ago and now I can see that it is outdated. Too bad there's no C99 standard for 64 bit types!

Thanks for the information!

Ron
User avatar
Ron Murawski
 
Posts: 352
Joined: 26 Sep 2004, 21:50
Location: Schenectady, NY, USA

Re: Tips & tricks

Postby Ilari Pihlajisto » 23 Apr 2008, 21:03

Too bad there's no C99 standard for 64 bit types!


According to the Open Group there is: http://www.opengroup.org/onlinepubs/009 ... int.h.html

The relevant part is:
If an implementation provides integer types with width 64 that meet these requirements, then the following types are required: int64_t uint64_t
[/quote]
User avatar
Ilari Pihlajisto
 
Posts: 78
Joined: 18 Jul 2005, 06:58

Re: Tips & tricks

Postby Piotr Cichy » 23 Apr 2008, 22:48

Tord Romstad wrote:My "most wanted trick": Is there any way to detect at compile-time whether you are running on a 32-bit or 64-bit CPU?


Maybe this can help:

Code: Select all
#if (sizeof(int)==8)
#define CPU_64_BIT
#endif
User avatar
Piotr Cichy
 
Posts: 47
Joined: 03 Oct 2004, 11:30
Location: Kalisz, Poland

Re: Tips & tricks

Postby Tord Romstad » 24 Apr 2008, 07:24

Ilari Pihlajisto wrote:
Tord Romstad wrote:My "most wanted trick": Is there any way to detect at compile-time whether you are running on a 32-bit or 64-bit CPU?
Tord


I don't know of anything that will work on every platform, but this seems to cover a lot of them:
Code: Select all
#if defined(__LP64__) || defined(__powerpc64__) || defined(__64BIT__) || defined(_WIN64)
  #define _64_BIT
#else
  #define _32_BIT
#endif

Thanks!

I'll try it. As long as it works in Mac OS X, Linux and Windows, I'm happy. Thanks also for bringing inttypes.h to my attention -- I wasn't aware of the existence of this header file. Very useful.

Tord
User avatar
Tord Romstad
 
Posts: 639
Joined: 09 Oct 2004, 12:49
Location: Oslo, Norway

Re: Tips & tricks

Postby Tord Romstad » 24 Apr 2008, 07:27

Hi Piotr!

Piotr Cichy wrote:
Tord Romstad wrote:My "most wanted trick": Is there any way to detect at compile-time whether you are running on a 32-bit or 64-bit CPU?


Maybe this can help:

Code: Select all
#if (sizeof(int)==8)
#define CPU_64_BIT
#endif


Thanks, but this doesn't work on all 64-bit systems. sizeof(int) is 8 in 64-bit Linux, but 4 in 64-bit Mac OS X. I am not sure about Windows.

Tord
User avatar
Tord Romstad
 
Posts: 639
Joined: 09 Oct 2004, 12:49
Location: Oslo, Norway

Re: Tips & tricks

Postby Sven Schüle » 24 Apr 2008, 08:51

Tord Romstad wrote:Thanks also for bringing inttypes.h to my attention

I would prefer to use "stdint.h" instead since it is also available in VC++ while "inttypes.h" isn't. You get the same "int<N>_t"/"uint<N>_t" typedefs from both simply because the C99 header file "inttypes.h" #includes the C and C++ standard header file "stdint.h".

Sven
User avatar
Sven Schüle
 
Posts: 240
Joined: 26 Sep 2004, 20:19
Location: Berlin, Germany

Re: Tips & tricks

Postby Teemu Pudas » 24 Apr 2008, 08:57

intptr_t (C99) or ptrdiff_t (barring a compiler that enforces a limit on array size) should work.
Teemu Pudas
 
Posts: 124
Joined: 16 Apr 2007, 14:03

Re: Tips & tricks

Postby Ilari Pihlajisto » 24 Apr 2008, 09:00

I would prefer to use "stdint.h" instead since it is also available in VC++ while "inttypes.h" isn't.


Thanks, I wasn't aware of that. I usually include inttypes.h because I also need the macros for printing 64-bit values.
User avatar
Ilari Pihlajisto
 
Posts: 78
Joined: 18 Jul 2005, 06:58

Next

Return to Programming and Technical Discussions

Who is online

Users browsing this forum: No registered users and 27 guests