C 中的 Extern - 我做错了什么?

Extern in C - what am I doing wrong?

我正在玩,用 C 做一个小棋局,因为我已经很多年没有接触 C 了。

我的主要是一个非常简单的测试:

#include "ChessGame.h"

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

InitializeNewGame() 将清除一些缓冲区,并初始化电路板。棋盘是一个简单的结构,定义在:

chessBoardStructure.h:

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

struct chessboard* board;

调用 initialize 时,它​​使用一个名为 Chessboard.h 的 header。 header 负责检查用户是否遵守规则。它还知道如何初始化板。

chessBoard.c

#include "chessBoardStructure.h"

extern struct chessboard * board;

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

现在,根据我的理解,我现在应该已经定义了全局变量 board。并验证我在 InitializeNewGame() 调用 InitializeBoard() 后打印出电路板。一切似乎都很好。

现在 InitializeGame() returns 到 main,并且 onLift() 被调用。这应该验证一些规则。问题是,当 onLift() 在 ChessGame.c 中被调用为:

ChessGame.c 外部结构棋盘*棋盘;

void onLift(char col, char row)
{

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

    /* Do stuff */

}

棋盘上满是 -51。当我在 header 的板上设置手表时,我看到它正在初始化,然后当 InitializeGame() 退出范围时,它变成了好的 ol' -51。

我在这里做错了什么?

我想念 C++。 :-)

谢谢!

编辑小例子 我尝试按照建议更改 extern,但发生了同样的事情。 请参阅以下示例。

main.c

#include "a.h"

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

    return 0;
}

(Headers 未显示,因为只是声明)

a.c

#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]);
}

b.c

#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;

你搞错了。

这应该在 "chessBoard.c".

struct chessboard* board;

这应该在您的 header

extern struct chessboard * board;

因为这会告诉所有你包含它的文件存在变量 board 在某处和在 link 时间声明,它将使用你在 "chessBoard.c"

按照您目前的方式,每个包含 header 的 C 文件都将拥有自己独特的 board

版本

extern struct chessboard * board; 没有 定义 任何东西;它只是声明标识符 board 并且它是指向某处 struct chessboard 的类型指针。

struct chessboard* board; 是一个(暂定的)定义。它定义了具有外部链接和静态存储持续时间的单个变量。但是,您已将其放入包含的源文件中,该文件包含在多个位置。因此在 #include 这个文件的每个地方都会有一个 board.

的冲突定义

Linux 上的 GCC 将在单独的翻译单元中合并多个定义,但 C 标准没有说明这一点。相反,它说 (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.

在您的代码中,同一个标识符有多个 定义 ,这将导致您的程序具有未定义的行为,因为 C11 4p2:

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


但是(我猜是)POSIX 规定了通用扩展名 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).