简体   繁体   中英

Extern in C - what am I doing wrong?

I'm playing around, making a small chessgame in C, cause I haven't touched C for years.

My main is a pretty simple test:

#include "ChessGame.h"

int main()
{
    initializeNewGame();
    onLift('a', '2');
    onSet('a', '3');
}

InitializeNewGame() is going to clear some buffers, and initialize the board. The board is a simple struct, defined in:

chessBoardStructure.h:

struct chessboard
{
    char board[8][8];
};

struct chessboard* board;

When initialize is called, it utilizes a header called Chessboard.h. This header has the responsibility of checking that the user is following the rules. It also knows how to initalize the board.

chessBoard.c

#include "chessBoardStructure.h"

extern struct chessboard * board;

void initializeBoard()
{
    board = malloc(sizeof(struct chessboard));
    /* Sets the array to the right chars */
 }

Now, from my understanding, I should now have defined the global variable, board. And to verify I print out the board after InitializeBoard() has been called from InitializeNewGame() . All seems fine.

Now the InitializeGame() returns to main, and onLift() is called. This should verify some rules. The problem is, when onLift() is called in ChessGame.c as:

ChessGame.c extern struct chessboard* board;

void onLift(char col, char row)
{

    short err = getValidMoves(liftedCol, liftedRow, &validEndPoints, &validRoads, board);
    if (err == -1)
        handleBadPiece();

    /* Do stuff */

}

The board is just full of -51. When I set a watch on the board in the header, I see it being initialized, and then when InitializeGame() exits scope, it becomes the good ol' -51.

What am I doing wrong here?

I miss C++. :-)

Thank you!

Edit small example I tried changing the extern around as proposed, but the same thing happened. See the below example.

main.c

#include "a.h"

int main()
{
    masterInitialize();
    printData();

    return 0;
}

(Headers not shown, due to just declarations)

ac

#include "a.h"
#include "b.h"
#include "struct.h"
#include <stdio.h>

struct mystruct* datastruct;

void masterInitialize()
{
    initializeDataStruct();
}

void printData()
{
    for (int i = 0; i < 10; i++)
        printf("Data: %c\n", datastruct->data[i]);
}

bc

#include "b.h"
#include "struct.h"
#include <stdlib.h>

struct mystruct* datastruct;

void initializeDataStruct()
{
    datastruct = malloc(sizeof(struct mystruct));
    for (int i = 0; i < 10; i++)
        datastruct->data[i] = 1;
}

struct.h

struct mystruct
{
    char data[10];
};

extern struct mystruct* datastruct;

You've got things the wrong way around.

This should be in "chessBoard.c".

struct chessboard* board;

and this should be in your header

extern struct chessboard * board;

As that'll tell all the files where you include it that there exists the variable board declared somewhere and at link time, it'll use the one you've declared in "chessBoard.c"

With the way you have it currently, each C file that includes the header will have it's own unique version of board

extern struct chessboard * board; doesn't define anything; it just declares the identifier board and that it is of type pointer to struct chessboard somewhere.

struct chessboard* board; is a (tentative) definition. It defines a single variable with external linkage and static storage duration. However, you've put it into the included source file, which is included in several places. Thus in every place that #include s this file will have a conflicting definition of board .

GCC on Linux will merge multiple definitions in separate translation units, but the C standard doesn't state that. Instead it says ( C11 6.9 :

5 [...] If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

In your code there were multiple definitions for the same identifier, which will cause your program to have undefined behaviour, because C11 4p2 :

If a ''shall'' or ''shall not'' requirement that appears outside of a constraint or runtime- constraint is violated, the behavior is undefined. [...]


However (I guess it is) POSIX prescribes the common extension J.5.11 :

J.5.11 Multiple external definitions

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern ; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM