1

I've recently started working on a chess engine, and am having trouble with a function to apply moves to the board. I have a structure type for the board state, and another to store moves. These are both in my header file below.

#ifndef DECLARATIONS_H
#define DECLARATIONS_H

#include <stdbool.h>

#define BOARD_SIZE 120

typedef struct move {
    int startingSquare;
    int endingSquare;
    int promotionPiece;
} move;

typedef struct boardState {
    int board[BOARD_SIZE];
    bool whoseTurn;
    int ply;
    int threeMoveRuleCount;
    int fiftyMoveRuleCount;
    bool whiteCastleKingside;
    bool whiteCastleQueenside;
    bool blackCastleKingside;
    bool blackCastleQueenside;
    int enPassant;
    float evaluation;
    move previousMove;
} boardState;

boardState currentBoard;

#endif

Main.c calls the "Process Move" function from movegeneration.c. It passes one of the boardstate types and one of the move types:

#include <stdio.h>
#include <string.h>
#include "declarations.h"

int main () {

    move firstMove;
    firstMove.startingSquare = 35;
    firstMove.endingSquare = 55;
    firstMove.promotionPiece = 0;

    printf("Value of firstMove.endingSquare: %d\n", firstMove.endingSquare);
    printf("Value of firstMove.startingSquare: %d\n", firstMove.startingSquare);
    printf("Value of firstMove.promotionPiece: %d\n", firstMove.promotionPiece);
    processMove(currentBoard, firstMove);

    return 0;
}

Below is movegeneration.c, which contains the function to process the move:

#include <stdio.h>
#include "declarations.h"

boardState processMove(boardState, move);

boardState processMove(boardState oldBoardState, move moveToApply) {

    boardState newBoardState = oldBoardState;
    printf("Value of moveToApply.endingSquare: %d\n", moveToApply.endingSquare);
    printf("Value of moveToApply.startingSquare: %d\n", moveToApply.startingSquare);
    printf("Value of moveToApply.promotionPiece: %d\n", moveToApply.promotionPiece);
    return newBoardState;
}

And here's the program output:

Value of firstMove.endingSquare: 55
Value of firstMove.startingSquare: 35
Value of firstMove.promotionPiece: 0
Value of moveToApply.endingSquare: 0
Value of moveToApply.startingSquare: 55
Value of moveToApply.promotionPiece: 1996058613

This isn't all the code from the .c files, but it's everything relevant here. What makes this bizarre is that the values of the move change as soon as I call the function. When I put all the code into one large .c file and compile that way, the problem goes away, but I'm trying to keep the code separate to stay organized. This one has me completely stumped. I'd appreciate any help!

Levi
  • 23
  • 3
  • 1
    A variable definition `boardState currentBoard;` is in the header file. I guess this could look like you would compile `movegeneration.c` then changed the members inside `struct move` structure and compiled `main.c` and linked. Does the problem reproduce if your re-compile everything? – KamilCuk Feb 07 '20 at 03:27

1 Answers1

2

There's at least 2 problems here, causing undefined behaviour.

Firstly, there are multiple definitions of boardState currentBoard; . Remember that #include is a plain text replacement, so both of your c files end up with a definition of that object. See here for an in-depth explanation with examples.

If you want to have a global object accessible from multiple translation units then the header file should contain a declaration only (i.e. prepend extern to the current line), and exactly one of the .c files should contain the definition.

Secondly, in main() you call an undeclared function processMove. If you compile in standard mode then the compiler should generate an error message. This is likely the cause of your symptoms, and I would strongly recommend invoking your compiler in modern standard mode with a high diagnostic level, as it would have saved you a lot of time to find out about this problem sooner.

To fix this, the declaration boardState processMove(boardState, move); should be in declarations.h.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • [The missing `extern` is "fine" in C](https://stackoverflow.com/q/3095861/589924). But it's best to be explicit, of course. – ikegami Feb 07 '20 at 04:00
  • @ikegami your link pertains to the same tentative definition being repeated twice in one translation unit, however in this code it appears in multiple translation units. Which causes multiple external definitions. – M.M Feb 07 '20 at 04:07
  • There's no mention that the tentative declaration has to be in the same translation unit, and `gcc` is fine with the `extern` being left out (even with `-std=c99`). Neither are these facts are definitive, but they do seem to contradict your claim. – ikegami Feb 07 '20 at 04:13
  • 1
    @ikegami The standard is authoritative , you can read that or see the relevant info in Jerry Coffin's answer. It is undefined behaviour with no diagnostic required. Undefined behaviour means anything can happen , and you saw gcc do something, therefore gcc is consistent with my claim – M.M Feb 07 '20 at 05:02
  • That fixed it! Thanks so much! – Levi Feb 08 '20 at 04:50