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).
我正在玩,用 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).