Page 1 of 2

Tips & tricks

PostPosted: 17 Apr 2008, 12:21
by Fermin Serrano
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

Re: Tips & tricks

PostPosted: 17 Apr 2008, 18:50
by Ron Murawski
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

Re: Tips & tricks

PostPosted: 19 Apr 2008, 15:05
by Pradu
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.

Re: Tips & tricks

PostPosted: 19 Apr 2008, 18:09
by H.G.Muller
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.

Re: Tips & tricks

PostPosted: 20 Apr 2008, 17:42
by Ron Murawski
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

Re: Tips & tricks

PostPosted: 20 Apr 2008, 17:53
by Ron Murawski
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

Re: Tips & tricks

PostPosted: 20 Apr 2008, 19:56
by Ilari Pihlajisto
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

Re: Tips & tricks

PostPosted: 22 Apr 2008, 04:48
by Zach Wegner
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.

Re: Tips & tricks

PostPosted: 23 Apr 2008, 00:33
by Ron Murawski
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

Re: Tips & tricks

PostPosted: 23 Apr 2008, 08:09
by Tord Romstad
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

Re: Tips & tricks

PostPosted: 23 Apr 2008, 12:15
by Ilari Pihlajisto
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.

Re: Tips & tricks

PostPosted: 23 Apr 2008, 12:32
by Ilari Pihlajisto
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

Re: Tips & tricks

PostPosted: 23 Apr 2008, 16:57
by Ron Murawski
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

Re: Tips & tricks

PostPosted: 23 Apr 2008, 21:03
by Ilari Pihlajisto
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]

Re: Tips & tricks

PostPosted: 23 Apr 2008, 22:48
by Piotr Cichy
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

Re: Tips & tricks

PostPosted: 24 Apr 2008, 07:24
by Tord Romstad
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

Re: Tips & tricks

PostPosted: 24 Apr 2008, 07:27
by Tord Romstad
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

Re: Tips & tricks

PostPosted: 24 Apr 2008, 08:51
by Sven Schüle
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

Re: Tips & tricks

PostPosted: 24 Apr 2008, 08:57
by Teemu Pudas
intptr_t (C99) or ptrdiff_t (barring a compiler that enforces a limit on array size) should work.

Re: Tips & tricks

PostPosted: 24 Apr 2008, 09:00
by Ilari Pihlajisto
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.